From 1e468ea75db5ae117683078a9a44a0945cf863aa Mon Sep 17 00:00:00 2001 From: pelya Date: Mon, 14 Feb 2011 12:05:30 +0000 Subject: [PATCH] Added bzip2 lib and Quake (thanks to Lubomyr) --- .../application/quake/AndroidAppSettings.cfg | 34 + .../quake/AndroidData/quake-data.zip | Bin 0 -> 22 bytes project/jni/application/quake/icon.png | Bin 0 -> 32783 bytes project/jni/application/quake/makefile | 133 + .../quake/quake-r2tec-androidsdl.diff | 89 + .../application/quake/source/FixedPointMath.c | 344 ++ .../application/quake/source/FixedPointMath.h | 247 + .../jni/application/quake/source/LogFloat.c | 113 + .../jni/application/quake/source/LogFloat.h | 10 + .../jni/application/quake/source/adivtab.h | 1077 ++++ project/jni/application/quake/source/anorms.h | 183 + .../jni/application/quake/source/bspfile.h | 333 ++ .../jni/application/quake/source/cd_null.c | 55 + .../jni/application/quake/source/cdaudio.h | 33 + project/jni/application/quake/source/chase.c | 149 + .../jni/application/quake/source/cl_demo.c | 475 ++ .../jni/application/quake/source/cl_input.c | 649 ++ .../jni/application/quake/source/cl_main.c | 1277 ++++ .../jni/application/quake/source/cl_parse.c | 1759 ++++++ .../jni/application/quake/source/cl_tent.c | 713 +++ project/jni/application/quake/source/client.h | 530 ++ project/jni/application/quake/source/cmd.c | 804 +++ project/jni/application/quake/source/cmd.h | 120 + project/jni/application/quake/source/common.c | 1879 ++++++ project/jni/application/quake/source/common.h | 198 + .../jni/application/quake/source/console.c | 641 ++ .../jni/application/quake/source/console.h | 46 + project/jni/application/quake/source/cpu.c | 156 + project/jni/application/quake/source/cpu.h | 40 + project/jni/application/quake/source/crc.c | 81 + project/jni/application/quake/source/crc.h | 24 + project/jni/application/quake/source/cvar.c | 310 + project/jni/application/quake/source/cvar.h | 109 + project/jni/application/quake/source/d_edge.c | 738 +++ project/jni/application/quake/source/d_fill.c | 88 + .../jni/application/quake/source/d_iface.h | 304 + project/jni/application/quake/source/d_init.c | 240 + .../jni/application/quake/source/d_local.h | 160 + .../jni/application/quake/source/d_modech.c | 161 + project/jni/application/quake/source/d_part.c | 359 ++ .../jni/application/quake/source/d_polyse.c | 1209 ++++ project/jni/application/quake/source/d_scan.c | 594 ++ project/jni/application/quake/source/d_sky.c | 207 + .../jni/application/quake/source/d_sprite.c | 839 +++ project/jni/application/quake/source/d_surf.c | 571 ++ project/jni/application/quake/source/d_vars.c | 70 + .../jni/application/quake/source/d_zpoint.c | 67 + project/jni/application/quake/source/draw.c | 938 +++ project/jni/application/quake/source/draw.h | 40 + project/jni/application/quake/source/host.c | 1137 ++++ .../jni/application/quake/source/host_cmd.c | 3450 +++++++++++ project/jni/application/quake/source/input.h | 34 + project/jni/application/quake/source/io.h | 29 + project/jni/application/quake/source/jz4740.h | 5212 +++++++++++++++++ project/jni/application/quake/source/keys.c | 798 +++ project/jni/application/quake/source/keys.h | 134 + .../jni/application/quake/source/mathlib.c | 1224 ++++ .../jni/application/quake/source/mathlib.h | 146 + project/jni/application/quake/source/menu.c | 3496 +++++++++++ project/jni/application/quake/source/menu.h | 36 + project/jni/application/quake/source/model.c | 3498 +++++++++++ project/jni/application/quake/source/model.h | 605 ++ .../jni/application/quake/source/modelgen.h | 157 + project/jni/application/quake/source/mplane.h | 21 + project/jni/application/quake/source/net.h | 337 ++ .../jni/application/quake/source/net_bsd.c | 93 + .../jni/application/quake/source/net_dgrm.c | 1400 +++++ .../jni/application/quake/source/net_dgrm.h | 34 + .../jni/application/quake/source/net_loop.c | 270 + .../jni/application/quake/source/net_loop.h | 33 + .../jni/application/quake/source/net_main.c | 1037 ++++ .../jni/application/quake/source/net_ser.h | 33 + .../jni/application/quake/source/net_udp.c | 422 ++ .../jni/application/quake/source/net_udp.h | 39 + .../jni/application/quake/source/net_vcr.c | 167 + .../jni/application/quake/source/net_vcr.h | 37 + .../jni/application/quake/source/net_wins.h | 39 + .../jni/application/quake/source/net_wipx.h | 39 + .../jni/application/quake/source/nonintel.c | 70 + .../jni/application/quake/source/pr_cmds.c | 3198 ++++++++++ .../jni/application/quake/source/pr_comp.h | 180 + .../jni/application/quake/source/pr_edict.c | 1567 +++++ .../jni/application/quake/source/pr_exec.c | 979 ++++ .../jni/application/quake/source/progdefs.h | 24 + .../jni/application/quake/source/progdefs.q1 | 143 + project/jni/application/quake/source/progs.h | 170 + .../jni/application/quake/source/protocol.h | 167 + .../jni/application/quake/source/quakedef.h | 423 ++ .../jni/application/quake/source/r_aclip.c | 651 ++ .../jni/application/quake/source/r_alias.c | 1540 +++++ project/jni/application/quake/source/r_bsp.c | 837 +++ project/jni/application/quake/source/r_draw.c | 1936 ++++++ project/jni/application/quake/source/r_edge.c | 1457 +++++ .../jni/application/quake/source/r_efrag.c | 489 ++ .../jni/application/quake/source/r_light.c | 444 ++ .../jni/application/quake/source/r_local.h | 428 ++ project/jni/application/quake/source/r_main.c | 2028 +++++++ project/jni/application/quake/source/r_misc.c | 568 ++ project/jni/application/quake/source/r_part.c | 1498 +++++ .../jni/application/quake/source/r_shared.h | 215 + project/jni/application/quake/source/r_sky.c | 306 + .../jni/application/quake/source/r_sprite.c | 749 +++ project/jni/application/quake/source/r_surf.c | 937 +++ project/jni/application/quake/source/r_vars.c | 39 + project/jni/application/quake/source/render.h | 257 + project/jni/application/quake/source/sbar.c | 2190 +++++++ project/jni/application/quake/source/sbar.h | 40 + project/jni/application/quake/source/screen.c | 1158 ++++ project/jni/application/quake/source/screen.h | 57 + project/jni/application/quake/source/server.h | 356 ++ project/jni/application/quake/source/slist.c | 128 + project/jni/application/quake/source/slist.h | 39 + .../jni/application/quake/source/snd_dma.c | 1022 ++++ .../jni/application/quake/source/snd_mem.c | 341 ++ .../jni/application/quake/source/snd_mix.c | 398 ++ .../jni/application/quake/source/snd_sdl.c | 109 + project/jni/application/quake/source/sound.h | 177 + .../jni/application/quake/source/spritegn.h | 110 + .../jni/application/quake/source/sv_main.c | 2208 +++++++ .../jni/application/quake/source/sv_move.c | 789 +++ .../jni/application/quake/source/sv_phys.c | 1680 ++++++ .../jni/application/quake/source/sv_user.c | 721 +++ project/jni/application/quake/source/sys.h | 71 + .../jni/application/quake/source/sys_r2-tec.h | 30 + .../jni/application/quake/source/sys_sdl.c | 514 ++ project/jni/application/quake/source/vid.h | 85 + .../jni/application/quake/source/vid_sdl.c | 576 ++ project/jni/application/quake/source/view.c | 1894 ++++++ project/jni/application/quake/source/view.h | 36 + project/jni/application/quake/source/wad.c | 159 + project/jni/application/quake/source/wad.h | 75 + project/jni/application/quake/source/world.c | 1727 ++++++ project/jni/application/quake/source/world.h | 101 + project/jni/application/quake/source/zone.c | 939 +++ project/jni/application/quake/source/zone.h | 131 + project/jni/bzip2/Android.mk | 21 + project/jni/bzip2/CHANGES | 327 ++ project/jni/bzip2/LICENSE | 42 + project/jni/bzip2/Makefile | 217 + project/jni/bzip2/Makefile-libbz2_so | 59 + project/jni/bzip2/README | 215 + project/jni/bzip2/README.COMPILATION.PROBLEMS | 58 + project/jni/bzip2/README.XML.STUFF | 45 + project/jni/bzip2/blocksort.c | 1094 ++++ project/jni/bzip2/bzlib.c | 1572 +++++ project/jni/bzip2/bzlib_private.h | 509 ++ project/jni/bzip2/compress.c | 672 +++ project/jni/bzip2/crctable.c | 104 + project/jni/bzip2/decompress.c | 646 ++ project/jni/bzip2/huffman.c | 205 + project/jni/bzip2/include/bzlib.h | 282 + project/jni/bzip2/randtable.c | 84 + 152 files changed, 88466 insertions(+) create mode 100644 project/jni/application/quake/AndroidAppSettings.cfg create mode 100644 project/jni/application/quake/AndroidData/quake-data.zip create mode 100644 project/jni/application/quake/icon.png create mode 100644 project/jni/application/quake/makefile create mode 100644 project/jni/application/quake/quake-r2tec-androidsdl.diff create mode 100644 project/jni/application/quake/source/FixedPointMath.c create mode 100644 project/jni/application/quake/source/FixedPointMath.h create mode 100644 project/jni/application/quake/source/LogFloat.c create mode 100644 project/jni/application/quake/source/LogFloat.h create mode 100644 project/jni/application/quake/source/adivtab.h create mode 100644 project/jni/application/quake/source/anorms.h create mode 100644 project/jni/application/quake/source/bspfile.h create mode 100644 project/jni/application/quake/source/cd_null.c create mode 100644 project/jni/application/quake/source/cdaudio.h create mode 100644 project/jni/application/quake/source/chase.c create mode 100644 project/jni/application/quake/source/cl_demo.c create mode 100644 project/jni/application/quake/source/cl_input.c create mode 100644 project/jni/application/quake/source/cl_main.c create mode 100644 project/jni/application/quake/source/cl_parse.c create mode 100644 project/jni/application/quake/source/cl_tent.c create mode 100644 project/jni/application/quake/source/client.h create mode 100644 project/jni/application/quake/source/cmd.c create mode 100644 project/jni/application/quake/source/cmd.h create mode 100644 project/jni/application/quake/source/common.c create mode 100644 project/jni/application/quake/source/common.h create mode 100644 project/jni/application/quake/source/console.c create mode 100644 project/jni/application/quake/source/console.h create mode 100644 project/jni/application/quake/source/cpu.c create mode 100644 project/jni/application/quake/source/cpu.h create mode 100644 project/jni/application/quake/source/crc.c create mode 100644 project/jni/application/quake/source/crc.h create mode 100644 project/jni/application/quake/source/cvar.c create mode 100644 project/jni/application/quake/source/cvar.h create mode 100644 project/jni/application/quake/source/d_edge.c create mode 100644 project/jni/application/quake/source/d_fill.c create mode 100644 project/jni/application/quake/source/d_iface.h create mode 100644 project/jni/application/quake/source/d_init.c create mode 100644 project/jni/application/quake/source/d_local.h create mode 100644 project/jni/application/quake/source/d_modech.c create mode 100644 project/jni/application/quake/source/d_part.c create mode 100644 project/jni/application/quake/source/d_polyse.c create mode 100644 project/jni/application/quake/source/d_scan.c create mode 100644 project/jni/application/quake/source/d_sky.c create mode 100644 project/jni/application/quake/source/d_sprite.c create mode 100644 project/jni/application/quake/source/d_surf.c create mode 100644 project/jni/application/quake/source/d_vars.c create mode 100644 project/jni/application/quake/source/d_zpoint.c create mode 100644 project/jni/application/quake/source/draw.c create mode 100644 project/jni/application/quake/source/draw.h create mode 100644 project/jni/application/quake/source/host.c create mode 100644 project/jni/application/quake/source/host_cmd.c create mode 100644 project/jni/application/quake/source/input.h create mode 100644 project/jni/application/quake/source/io.h create mode 100644 project/jni/application/quake/source/jz4740.h create mode 100644 project/jni/application/quake/source/keys.c create mode 100644 project/jni/application/quake/source/keys.h create mode 100644 project/jni/application/quake/source/mathlib.c create mode 100644 project/jni/application/quake/source/mathlib.h create mode 100644 project/jni/application/quake/source/menu.c create mode 100644 project/jni/application/quake/source/menu.h create mode 100644 project/jni/application/quake/source/model.c create mode 100644 project/jni/application/quake/source/model.h create mode 100644 project/jni/application/quake/source/modelgen.h create mode 100644 project/jni/application/quake/source/mplane.h create mode 100644 project/jni/application/quake/source/net.h create mode 100644 project/jni/application/quake/source/net_bsd.c create mode 100644 project/jni/application/quake/source/net_dgrm.c create mode 100644 project/jni/application/quake/source/net_dgrm.h create mode 100644 project/jni/application/quake/source/net_loop.c create mode 100644 project/jni/application/quake/source/net_loop.h create mode 100644 project/jni/application/quake/source/net_main.c create mode 100644 project/jni/application/quake/source/net_ser.h create mode 100644 project/jni/application/quake/source/net_udp.c create mode 100644 project/jni/application/quake/source/net_udp.h create mode 100644 project/jni/application/quake/source/net_vcr.c create mode 100644 project/jni/application/quake/source/net_vcr.h create mode 100644 project/jni/application/quake/source/net_wins.h create mode 100644 project/jni/application/quake/source/net_wipx.h create mode 100644 project/jni/application/quake/source/nonintel.c create mode 100644 project/jni/application/quake/source/pr_cmds.c create mode 100644 project/jni/application/quake/source/pr_comp.h create mode 100644 project/jni/application/quake/source/pr_edict.c create mode 100644 project/jni/application/quake/source/pr_exec.c create mode 100644 project/jni/application/quake/source/progdefs.h create mode 100644 project/jni/application/quake/source/progdefs.q1 create mode 100644 project/jni/application/quake/source/progs.h create mode 100644 project/jni/application/quake/source/protocol.h create mode 100644 project/jni/application/quake/source/quakedef.h create mode 100644 project/jni/application/quake/source/r_aclip.c create mode 100644 project/jni/application/quake/source/r_alias.c create mode 100644 project/jni/application/quake/source/r_bsp.c create mode 100644 project/jni/application/quake/source/r_draw.c create mode 100644 project/jni/application/quake/source/r_edge.c create mode 100644 project/jni/application/quake/source/r_efrag.c create mode 100644 project/jni/application/quake/source/r_light.c create mode 100644 project/jni/application/quake/source/r_local.h create mode 100644 project/jni/application/quake/source/r_main.c create mode 100644 project/jni/application/quake/source/r_misc.c create mode 100644 project/jni/application/quake/source/r_part.c create mode 100644 project/jni/application/quake/source/r_shared.h create mode 100644 project/jni/application/quake/source/r_sky.c create mode 100644 project/jni/application/quake/source/r_sprite.c create mode 100644 project/jni/application/quake/source/r_surf.c create mode 100644 project/jni/application/quake/source/r_vars.c create mode 100644 project/jni/application/quake/source/render.h create mode 100644 project/jni/application/quake/source/sbar.c create mode 100644 project/jni/application/quake/source/sbar.h create mode 100644 project/jni/application/quake/source/screen.c create mode 100644 project/jni/application/quake/source/screen.h create mode 100644 project/jni/application/quake/source/server.h create mode 100644 project/jni/application/quake/source/slist.c create mode 100644 project/jni/application/quake/source/slist.h create mode 100644 project/jni/application/quake/source/snd_dma.c create mode 100644 project/jni/application/quake/source/snd_mem.c create mode 100644 project/jni/application/quake/source/snd_mix.c create mode 100644 project/jni/application/quake/source/snd_sdl.c create mode 100644 project/jni/application/quake/source/sound.h create mode 100644 project/jni/application/quake/source/spritegn.h create mode 100644 project/jni/application/quake/source/sv_main.c create mode 100644 project/jni/application/quake/source/sv_move.c create mode 100644 project/jni/application/quake/source/sv_phys.c create mode 100644 project/jni/application/quake/source/sv_user.c create mode 100644 project/jni/application/quake/source/sys.h create mode 100644 project/jni/application/quake/source/sys_r2-tec.h create mode 100644 project/jni/application/quake/source/sys_sdl.c create mode 100644 project/jni/application/quake/source/vid.h create mode 100644 project/jni/application/quake/source/vid_sdl.c create mode 100644 project/jni/application/quake/source/view.c create mode 100644 project/jni/application/quake/source/view.h create mode 100644 project/jni/application/quake/source/wad.c create mode 100644 project/jni/application/quake/source/wad.h create mode 100644 project/jni/application/quake/source/world.c create mode 100644 project/jni/application/quake/source/world.h create mode 100644 project/jni/application/quake/source/zone.c create mode 100644 project/jni/application/quake/source/zone.h create mode 100644 project/jni/bzip2/Android.mk create mode 100644 project/jni/bzip2/CHANGES create mode 100644 project/jni/bzip2/LICENSE create mode 100644 project/jni/bzip2/Makefile create mode 100644 project/jni/bzip2/Makefile-libbz2_so create mode 100644 project/jni/bzip2/README create mode 100644 project/jni/bzip2/README.COMPILATION.PROBLEMS create mode 100644 project/jni/bzip2/README.XML.STUFF create mode 100644 project/jni/bzip2/blocksort.c create mode 100644 project/jni/bzip2/bzlib.c create mode 100644 project/jni/bzip2/bzlib_private.h create mode 100644 project/jni/bzip2/compress.c create mode 100644 project/jni/bzip2/crctable.c create mode 100644 project/jni/bzip2/decompress.c create mode 100644 project/jni/bzip2/huffman.c create mode 100644 project/jni/bzip2/include/bzlib.h create mode 100644 project/jni/bzip2/randtable.c diff --git a/project/jni/application/quake/AndroidAppSettings.cfg b/project/jni/application/quake/AndroidAppSettings.cfg new file mode 100644 index 000000000..55dc247b1 --- /dev/null +++ b/project/jni/application/quake/AndroidAppSettings.cfg @@ -0,0 +1,34 @@ +# The application settings for Android libSDL port +AppSettingVersion=16 +LibSdlVersion=1.2 +AppName="Quake r2tec" +AppFullName=quake.r2tec.sdl +ScreenOrientation=h +InhibitSuspend=y +AppDataDownloadUrl="Data size is 1 Mb|quake-data.zip" +SdlVideoResize=y +SdlVideoResizeKeepAspect=n +NeedDepthBuffer=n +AppUsesMouse=y +AppNeedsTwoButtonMouse=n +AppNeedsArrowKeys=y +AppNeedsTextInput=y +AppUsesJoystick=n +AppHandlesJoystickSensitivity=y +AppUsesMultitouch=n +NonBlockingSwapBuffers=n +RedefinedKeys="LCTRL LCTRL INSERT LCTRL SPACE ESCAPE 7" +AppTouchscreenKeyboardKeysAmount=4 +AppTouchscreenKeyboardKeysAmountAutoFire=0 +RedefinedKeysScreenKb="LCTRL SLASH SPACE INSERT" +MultiABI=n +AppVersionCode=2010090601 +AppVersionName="2010.09.06.01" +CompiledLibraries="jpeg png sdl_ttf sdl_image sdl_mixer" +CustomBuildScript=n +AppCflags='-D_inline=inline' +AppLdflags='' +AppSubdirsBuild='' +AppUseCrystaXToolchain=y +AppCmdline='-winsize 480 320' +ReadmeText='^You may press "Home" now - the data will be downloaded in background' diff --git a/project/jni/application/quake/AndroidData/quake-data.zip b/project/jni/application/quake/AndroidData/quake-data.zip new file mode 100644 index 0000000000000000000000000000000000000000..15cb0ecb3e219d1701294bfdf0fe3f5cb5d208e7 GIT binary patch literal 22 NcmWIWW@Tf*000g10H*)| literal 0 HcmV?d00001 diff --git a/project/jni/application/quake/icon.png b/project/jni/application/quake/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1215d531627ea9caa958448d0aeadb6cbed9c014 GIT binary patch literal 32783 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+7>k44ofy`glX=O&z`&C3 z=LqiJ#!!MBL7Yq!g1`G_Z5*Qe)W-u^_7tGle zXv4rz-|Ok(7*Y}Ub}wti)a%0Q}cG^eQLlTa#es@2lQNxqy5Edopa%U*we|J}S5 z8pU4frzB3Do^pDMbyikZzlK0yc=-SBMK!Unzt8{iT|VGkfLYKh%{r04^}CP$4&S4w z`g{7` zG`$^cs=b>6bYe2^E?SZBm{38!A?uHCct(p0Zttw?uw_FUKSaPj)JTmJ6ewji*stznU_!joAQx&4~I zHB+bjKf-&SIV8rT{*=tA>t6DD-0Qb^1)kW>#*uOJTZ;ECrHK+Igy@sBzJ zw|2B%uYB+MzpU$Tc3y{hp7+h`*IxaPI{M#o>3>VsZGZR9oGE$c?Ae6O%#Z3y`zQbZ zoqg|dq=OB2TYBS#Yo;e`x0Q0oG{H6%vkSqFOy2!URQ@fjVb|U~>woW~|1w*(>-A5Gy57DOb@<{%KSe)3k-F*k zPyYXF$zb#QUOmemdoC^3J@rR8m|C{wT$p7P_w<&_zuQd?TbEPUhdY zXB-=ho45CJ-dWR=n3r^<+C)M6g>$(7s!3}dld?ktuetU#zn=0jpOq=}D&Jd8;j33e z79N~^<%2d*OlO zB7)!43JgruPVmmZW}tFms$46}{!2T8(ys?OEV!lk{yr1S9>Jzvho!cfow}YEx=&8m zA@M7hy?)sFJ$Em(?A)pICiwKE_iAeccT4Wqo|5-5{?x_?`~Pb_yno|X)Pb{C<^KI! z$HD#CbyL5rUwE6+#>w(EwJ{H$rSV5gce45FzvU8=SW*7>iWSRy@@C zu_I8MqvWfIEqAVNnYO4xf@omqSHbIR-^I(Z?CGq0#q-TXblQ5)Q~6tKqV_h56pN@v zMOjUK=fU-L<93IZZq*pDOqcbSFB5W>X?0pF;C@uS^7h60TZ^+> zn5Ber4HVCE8DG{hm}*xNpq~9@>D1IJNt}_J*ZEPI%W#XL?AfJtFQ#X-&s!L#@zv0MSv%_=2@NielIXjQO3oJ& zmIuc)&AP=e_3FRV&Bl3cQPUPq`<3i%>uVvAb?{<@_%t`CpZ>Qur189A`8qM?0SkZB zr2V?9oHIpb-v&s&?0LtjCo$(?$IhSMB0@5ncfPzPA$mGN>yFr8>!OQ)b02uF5>vJB z<(wC^`H(qxZuBKD$yWE>QOd`!^Zl$V)A+d2(Oj$CW19T3P}gL)SS7wlsRw0Kw6ASR zNl3e1;B)%>p&KgJJqkD4Ty8GXU%y=A0NchqmgcRNR+iBhU*%3be`Dc{OGnSki7N83 zEVn(TW}TR{(tcXsi6iSGTW{>%!SZ|h^u+s{yxzr#CL+HU zSe}eyY!ZquUa~t{so{XxqhB)&B+3jfwoYFux5szu!;}@A#j;L)1WSn79pkuHa8f1Sq{u7 zQ9rY$_efOKpL?nye?EE5xp#$keeV0N?(?#;Q8QVim{aU&oWZW?FA% zvHsGx!FlC;UZXoY0$yQVr3P-xx*3D!lnN%V?^f{6-66mtb}K9W%$BRB|1%vE7A#Cl zS+Vk4o2c&nn=?*rztFzkRP=pH%ei-Mdo+cYIX>%Hs`@nGr|Fhoj;seItQB~J+e?r2 z2+lR!m2Q$|rvB)`9wC`I6Iw#|{x#@lm@(&V%fpQ<3~M)~yGwuJ+2q)-klh;U74R%0 zb=ig=A^zDZ1`THtyr%i7rvALOxIsaKW6@T(-HTT$@B~*aPq;S0DJJ7SU;M7fq}y+b zbY9KvNR9owQRTQGw^5FP>QT1j$GL_!r?}3tI0)NsHh(-xk8#_Hg-^TR zY5nYrH(9-ZyCq+3k$Dpn&}XZyRZy6%YIh^Pb2j^`g2x5^dun%>>+K6^w>`aTLsE^{ zv~PR|t~fDiTof}+yr%JOYtWA7kad&Sgs1yEr|f*Kc+Qc%Q7o#!=z@aq3f*7NSsRx9 zGAfSs-7)Lcf%{(k2hDzQY&CY;vzt@suCJim>z-7F>Hhzt#2>aawkk?kZZLl4uXF5G zoJ{vG zzubFd$BoN#Zz#2HbP;=L*Dp5T`}Fy*y!_zRwW1aI`KoqyH@V--NVjB9x%~Ur!wbjWMVK$= zn0-t&p)^0=M}Na%iCy!41#la6t6q|jIA$^X!>`_pssZzlIjI#~X;#16xOLsJ{AE$E z{?|AzT)3=i;>x~b!qva3^0Sp$Zc8qnJlRkv##i9=5vGo2$wx1|xtZ5o)IKK3+;zxs z)x=Zt1G-ANvo@qgmgmI9wcpjw+E_07_t~key7dPRK6Sler^NMo)m_8BiQf)ru*I&O z65}iOLQZE|^6C>uAA9_qsq;=`!m4h`IijqV7e3A9U`Q|F-0Z$SC4bA5<4IM;ddtk8 zJS=8<&^S-5Z{6CX&k|?exM?mT?LB9M!ezG2lh+zpUKC1xwDzQpnS{sF?~2?eE&>&b z+cYNZXgU+*J>A6S?9`9V+S5X+5*%Y^Fdb2!F827=GrfxRaMgQO0nMkYvp@VgxNpZN zFJ`{{*PXT6S{t)!n5J!anZ&uraO(j^<=~3^KRrSD-YQ0}K96pNw$J`l*R!*%jbn?k z!se`lPVRq=k1_wZxqQNHR@Sv+QLnb=@@{#Mys*2kFJzB?@e_gSBRgkY{ytl|S2H|v zfoj#VisXP&9yimc39mjd>CC>!diweGq|2YAa-w5SwF3K+7cHO}F#KBXALfr;xFCTWEOy!gC{w6u`luxUIzM}WB%@J2- zW`{}U_vh3fV>`#jvE@qR;zqSITdr=KmASI~$MOPpmIGzn3+s||U2eQmyn9;asLxZb z2!)B4(z!I(8Xb}9-PtH{)m(IP+q1+dZ@Fjv+6R7BrlvG-$=nO*ef@h?;p2?_KUFLF z?B}dJwAJ@zMQ)lxnOS9$oNlqpBHPRxjJDB?3OoU_XFh3v{#f#Ud03=O#_Sw3{&IJe_y9`c#08+j`HacL*W(OMF&=-u%FTUdh8Tq;0=3I zQT1ob9$wnzv}fN&k@q>;2ThqCay8c0Buma*%c6h2^WY;l{WB}SA7W}ss97oOCT6`@ zb82Ja64_IKbR-03Ei#$&kuQ0ojJ&hU&6fvmyKryY^@^$KRJ{emia#2cE+$ty=l+O% zG2v71#LE{spT2DL_^`=Q-Mu)fOO#EFB{8X3Z5jXR<7)(2BP z(#lVNm9PHzlVdw?&rM-||0fTBpIvBSbV_!0_FO~dey*PKgsf)^IOKK*b1wSBwJdYy zye$Gv3p!3sU$92+R4ez3121N+?=OA2|Lw*0r8f^&9-MJgzt?UTmvMJ;J^KM^?Nx=d zru_Z%L1N8{Pe>2vB!9p=u1UWCpIm$$5SS8?qabp zYAtp7FHy~NI^{sr%XVAkrjOSyY0Qb8*Jga$>hYm2r9HbA$~@m*c5wFYQ-xKbeBbm> z9$5C!G2-HR(alvmlJd&MeMG~v%4zZzy9m7zn3k4JasVH7bV!T`LOMV zbzPQaTvH{Vw#czKlt=A|*cnmIy10n*&yr~YI<89$+(S00#mm2JsoU7MqJP#*CXE%Nh0~1gHba(@c+mDqxpDt`V zzM;U_#U~*Qdkrao3aY8}%e+zHXYjRc?pXRsQYa?ho!> zE!?rkNcQ-&l*e0jTPw=LIsMl59Q_yBdBfC*!MbfnV&GikXIBlUtx)68iZ$%I=_uTI z-S`NTXJ4Af$MgfInjTv6yYi33E#-6TzbmG>#iri@PD3;4hn6K`r zTq1LS?zv;$KZcEf-JwSJBUY@B6Q!K0N_igWB2kPKAsB`a#VpK;M#p8%0}J#RSpk61<<*lu<*U*@}4=uY5l$*yOwT+U>lJich6WrXcY z33rdZ`FlfJ`T4&dVQnBIi~g>D}$xj0&xi zY)xN|x905E`c$;6+Op@Ls?+=9*S{`aR5fwc@5`blT}qd24ELAIlo>s@|9Gk3PEy%| z9>%;2y0O-FUK7jSNeK2w?mQP_mE2cxO>V`PhdQ76`Zor$G&v{9a4 zymt*B-MRmM2w-b=mRQQ4V5ZQjxYFHYs^LV|6)NAPmwXF2`TDj0f}YdM^7TI-xfB(j zlgo49;>AV_)3fn{H{#~K?N<(d`RG||;&qMuri0?qY?X<{-TILSCO^$m_t8k?wwyWt z;Jd_Wt62}d4BGwSxy-c?r-=Op={qBCTz83nY`1!SUcI@%h4cJA3xuf+RngbL-9> zefqU>$IksS@$qk1W7ZvO-g~j4K9ix3_w%tXu5gp18~5KkDSB6VPGnW;JKv+`lk$E~ zy4St)LFTJ+!l`0Cy4506dVS>f?O zi}6EUDU)4Yt7LX5&1gP!;5QxE=ol*MtR zMlAo)i89W6VIHayM?_1x)jtdD5UxDG*?X_S>SN-ofBi^IUd+$e!*^`;Wah$>D1*3} zLPxrmn}6&3tR`Tyu}t7{fYE_N@6OE#O7Z{jxvu#I+YPb)f+=D~+VlFipyxBPk-@=syYfdwm;vnsyy{E{HMi2F6)M;-g)fu5d4`zQ5z^&Gmf*m9!m zp_=?2?T-hxc;&Bo`MCRS?>!4sJBH)STOYspk`OcNarfoRdkSYTM0mcA4|?5Y=~EpY zG)LrmypPyfr5#IJ&5$%?yU;B9TT+dsVc)V}KHH9FXB_^+X zs-nIeu`z$6%)!^sdF-U5VMVT|+Pz!%nBU92Jp4dIY_oTb;qC+6lZ|a6*~$(zWNanN(ir=*qBdv-|&B z3k566|G%(jJdn=AvA?2N>RpUP+h%X;lIxk;!XzJM8uVt}Y>+o%Q!laKbi;pm* z$h!u3xrT3)oA~l*(UvJoEH6*+ntmlRrtyg8+!>S91Xx_{W?Z@|zWVi^f~*{Yb>}#a z9IZ6GVXnrqzVF-Ni3{a!1if!#ed;&kSkr}oV+xPlc3s%|bemM5$o2F0ukp+an`3CQ z@S^0aLr(tE$5N7Nb^C5+t}y+3mT|%Ab+3-z`M+@KI=1M&vo$8 z?88>`=K0L+`j!nZUuT@$XLWR25fP6%L#Hm;Zxx@D z({)(8*!uB}J0g3wDY1r&9e;f0h{Cm7lA_(NMTytSN)N9zlr>y=Nd9D=(bVMiAND>< z+hxElaBF?~!{zF+Zv0_<(wRF??`lta{Um5kRi%dA9fJ@43?EdhS<5*Z*6VG5@RnE7 z!eq*IXL%d-`;3z#W(u=qBptYUV%L8LCZAhJ_GZqsZDr(OSn2Ljuh7T4f`!TE+~m0) zoE#_JzCP-Tu$MR}kz&HQch`FHzFyvA{{kIvTomfKd)Ds8d7pIM-SdJs#a@tkf8xf| z%*2&*-p@U4p*8)1S9*=$G1ISGrpbkk2A7T%>w?8mJVDz}PH z`^xG1y`tQ8yZuued|oaf+gZTB+#E`>QhD3SVqye=O+g zIV;GCVc8}HQGd6t)H{x-GHdNQx3V#mH^HtI;64 zsll*;C%58Mxz_D&g%6K;TLeS`c?2H6z47(Yes0U9(MJN;vdN3*`0^h<7s8iTV6$5P zf9#o$YkdC2+DCoj3A@pD#A@TA=Pf5A*U9WkdD?sB-uwk85*5{^H!fJxq{_q;$n&_R zE~T+9urK4${j+bSdUzLqD#$vXu*Y)63x9?WdpFAE#n0?nfA0H1>FglMC9Daq=G8vQ z3L1AER{k?R@!RmlYwwAD3z!&^{{D$`WYgd;aA@1koW%J`gvn^~b>#&j;#*dn4nBH6 zN~Z0+ncL%AO$K{x&d9U7u_c!3%lDjI!nom#j%|+!+r)`1{!7|z7g_F?@O|ojxz(*; zF4K_(91Pw}4r(iSEuz-Bi(PoWWhx)zfderqAMf)pZ26a>tQBv#*NfqVz~YksduH@^ z`4<@)y0EZ2EV5vJa9(JG_4fG6qDjYQJA7E$GD*}bXwllU0_W?~i_`W^;*yho*7tXA za)Hry;W#g@qgw*vzkDxon<@PJXHBfu-FA(V1a--M1xIdq>91K|di>im1s~1A^kokZ zc*?T7J@$LUZn3aOC*bV$@bZ*`6KfV|-sAnen=SG74VyW4?)ALh`m&y>p*>5s;PuwR zA5S89&*^&~o;UGeMC{|nlRE7F53cwb|E-fZYB=-HQ`sx%Lf*n_U124vQ}y$fx9CiB zXYkUtn*Yw>(Zn_lw@)b>SZ)6l)`Y3$<>(*3J-eu&d27Sv$$vL)+s>~xea9mCgF24M zChZ~49$yvDm2oWjQTXD@{hMNSd+PId1Kozd3op8UQ0(^;j5eGH!)mL=9Vzf zGrkz|zv1np{l1km7-r=89OY)%@}fGW&Ub!tT-uz}&8adE(oR`zwQP5&n8>&%LqE`N zdHo;DS1QV(f-<){p7yGIET1`NtM;;@_McXd1M+10#Fjot`pzVy?|b};NBx)LVkcI{ z0EcNF56{%@v3hA&D z<~_DGSga%??Ou9p=33?tVOQ%-n^d?fd@A3c$++|A!?A}mPe#}(wD2mH_xLNfUasd) z@KP77mz}ELINyie^PuOc3zyh6zLY;RwJ_qFu&bqKJLl&epMKpjw7o8T*;1pbLpdpa z&Wry3va(}KcRJp<{G|P3rJM{~p_5(YQsujD26y8%+%MOjtjROs33t!laru+2#o0H< zN`(b(oIbMY&GZKxdwcpMi;rD$_!d^s7BIica9QIfx5`#%<@|&9ZKA<^!c7O9 z!nxCy$Oq@W*pMcB;AF>_^$ZP+HaiQITNu3+(x26yU|P8LRKGGqkVfR6az@60b2AdW zi!}76EqOFoaqEuVDMIV|5l~OsuSoEld%`xG_T-HfXJ7i=c@AJ3cj4?MEgaH#sBTToaK5tnbYN`5s%j015Q!3dX3Xh zpP!bnWm;oAbL_P(r@ey`emUDop` zd*H{UuW@_g!|$z@W=@lrYM9?`%A6%#aWi7F?^==IQ)wv-(M<=YWiGhFn3CL^qjyoA zV~L5sSj4A0j0XzWdju~!J@Mjx+0*@cU;b}nX%J<6kZ@)Zi~fn3;?IuC+Q_+NF6ouL z?ATX*`PX8OCW}jTY{fTnyaXi|Okt3C_PnRNwa_AVR^#i*Zjatg?f&uR%<3DF_l1+0 zm@k}ez4GFKMT3K9IKu%x$t6GZbhwvae(qLnvFX?Wg$aS>e9h}?^!e%yR_H8ro%Z9B z=mxg{xfeZBdH=ICd5(Tc+-b2PjX~_Gi)NeSl-337e|&B|d-jHP_hiS~#~T*hlAm0B zV`B1W_fxxSmn=KL<8U#4LH0_4r=LGB75_rY=3OFpDKSw#HxeggQA2@ z?%D?jO-sz`cLkrC^6pyS#s=k?*IN`WBzom}gl$VMy%yvBme=^%tMj5PY_qaz-)y=1 zaOwGH{E-KmPHj&V$;w~hezZ8I^J#+rGWBzFK7W7oJz`g5#Wlu5nI8+c{3!8~I~Z_g z_KU2e2L&$OO3^BI-C=K*;_~Ru48|ShPkHw3uM%RP{mMX7M}T>6gV`uu*yOo{bus4VSGF*YH$nPtoU@;F*vj%)r#d zqi@#A!ccdJrALsX!HX#&!qNRqzTSb;+OrMpH96w986D{V^H28ao36SXkI{nAgWD@2}7Z{KBjwIp%P#Z`aI7*0Hz*S3y{M{Dbh>%nJVuS*rVKle)9 zSy}hHC(}&dr6_L-<8NBfsxU+1>ESOIB@@@oX$!IndN@&UOHG=uqX;YWhuurg3$e3o zViPzbRKU^vCc%51Ib*_6ivv@3O-Q&fN9VyYv5mUCSDk`QpYLRBSbR@kDtpEJV%5DY zMKUL6UR95t)*w5Bv7+GF{n`8OPkcFFa_#+j3>=Tv)S2u*9<<3L_UE3)b>GZZELP=T ze6{b(gDc%zdCgLOGq`_lRJN@6UJl1Hpdhv&EVA?*r{6C-HH7jb|wQje5eOVBfBDBjL za>#sUL# zndr}lcWNG%TzRHHRmwv%>8ICg{RK@{#zyBKyzg?l6EOd1;fG@}IWf07rWx?x$=UkH z|L5Or3<+ucIy3JvD`!o#6knMK_b%z$I@NanQ!Bnq5(r;b)$@&&<&WOMcs53b zr!Pv_RxlmV`?FKt@y7jjMveD7=SzFvleJDN^;Fz;B_tuv%>9xwb3yOzi)F{#6VlxM zdDJ%q-F)xA=#sGK_qiGmdny-6{9&DJ%KTE!D5qya-qQY*cWXUL43gZADh4tgI2|(m zvg57|3;kp??AokY7}(vnhJ266TDk8-jKhJtVj1mv|2aEv9`1MM2)pwr)#*s2)XT&3 zWHrsZvJ7;08 z!d9_WXupj1k;Te$SZ_#o7dtoK?ECuQowS}A^O_>9-PTiYNW49rl^`(N=FUy;EMK*$ z%PxGnoKY&dy+`Hr zqLLs{F(HP(t0o7|6YHqyoBDLa;fNz*C92%sQ{Q|p=U&XMusY?_E+fhA6k(Q^Tk4KJ z-~I9P-N^L{%Dz1x+<23xWQmLOeEM|k(jTUnn4Mhm`-*th_sI3Ft^9aH=5hbcJJa@A z9b;EFK78>^gX!UeOp+mWlQ@zaS&SUqnH1Xg?HAs?_Tx1+k7Zxog?SdTIB0y2WhpQ? zGPmu8L-UsO$a~#AIo`IBnX7BhC4BffC+yTAr~2Y$b?dg&+1E8(S+JBV^(4=M&VBX` zlMUMoK1x?F*6>g^)xQ|^VL%GN6Js8JND&F*Tv5sopmOpr@Zjc zwkC%^HCvh#G}!r61A{&mWUHLx`+EG!Ik}t_7L&7fzUX;#`NjFm&39*7?NsPw@K~TS zk#W+>H!hq4D?41Y6dE@=8YMTnXn8VBkbBg~WprQ$jz1{PY3?9vNI`*kJDD&;n9%e5VmYxr%n__of?l^PELSZh?1UGX9M-O$*A>iefF3SP(7?8~#-7Z=qQy!DQ=z(LRSefO1i z?S2^KzTlB@=FiL$#+NM4Qj8Zmr2~y4;`r4MADb9CIWy#=$rg>UxMWR3k$T}*ji;tR zn;>34O_DKN_G|kc&nF*aBpNi2%4EC!%d2^u;P>Am@MloN1hWm=%!2V=TIP)<+paqs z3f?+=^%N?>iC`cPF_lGk(r_=YsypP{U_)J^srdx2m+6 zs>dZhQLU%s@uM9-7X4tkRAAFM!RtcFS&qXm{{6hMV~^xt$q3G`-JkRW<3t&FbPq0? z$>If(%~zHc*mc>FT&kGxtvzb~A}w9aYjco!cp zxTc-;;#1U(=`Y+BM6C*|r5Pt4da=Lju)OKDU3>CkzZ6|^758I%{`o$u&O!0puN7t; z-f{0rw{-92$$1Ckf=ZUXo_6ci$@8oXOD5@Vr20MB^#}{89e?g zPDwFx*t(WasxokK>{o;HzWldqc{jGKz13T}a)-$($>+=bkKJ3wcBUtBfxD~kLeX4b z&O>2(zXaypQq+vsT)EeOiFUW9jKa%TjbE?kMO^J=7QJh!dSuVi zE9fq-bE^O0cfXKb9y*c=Z5v&p3?vnlWt644I2#;!9C}4h?N_^4zgi|k>%b+;y#c{9 zyY93os7%OBTKOc!UOeTZ=#vc_LVOrX5*;GWd@-6VdLSg~?R%aBjT3b8e6u?rB??U3 z_u}w@t+UnLZ`#DJjEUEIF3F<4``Cj^3o7Phy*g2Gj9Z-D{lT#veLGAnM2a8Z{E##^ zp?$vTw2858Mhx#xMLDoue(refSH?rTgA3p7dhvQuyNpqe8sh}FYq|;=R)QRhYQ%RX ziEr9y{FuSrwlpGZWw?zvLqzuKy-DZ4IK?< zL~ddUcOZ+ax>g(`!@oJlrmWUdW=fXk-dK7yp~uiPAmX3pshMGH7B{rHS3mpixc=SC z6J8uH%M;99KEIz_6FX7zQ4dd4t)qMS6Jd_lGX_OVe_rNlFj>|hS;B0{b8Fd=$j6t} zs_(4XaA>7Vc24r<7pdQP&4M-_t`G~X&o}Q;vd+=rJrWwmn(xPP@N4422$9#FcOS0% z(y%aMsz~EW7GLA|_|x}1Wi$6ppDU-eqNa1>rCgqg8Ok#ms`c+wNS}x}&}LPr!jNKf zzO`@`_jkdljMe-VdJG$`2JU`!>dX1|=)K7||9xG2$+vQcvx4#koki;#PQ5$BpgN6P z`tS?;>9Ggd{^f0(Z8oj?b#n0r#&7O3lkCdB_;EZhVE2DKA?kmE+Zp9M7G~#kQx5M~ zpdI{2RCA(zHcK6ggGFruPdfXemydU=8`du3&N%ge?YxV49*f{BRoBax9!s!yEKYGK{*7>7yorR&d2H1J$dRu`H)n|ovN+W?dk(L>H`~z7LNco&Y4CcP#IWe)B8f=HASYrCa`J8ReL>$4;?&x$#)ifhn_VCD&hW?@Sjvey^TK^!@P@#uN9c_jdVhz3jTJS5B*P zVx>#6c+fS6pvxirxo4CZ!it+8dtW?Op?Qy`d&l{;>Qkc~RG)7&yD)v~I^DXO-syb1 zf+C%6*6CEST=?%PCv&(fg6D57TWvw^B=)Em`s~H?9n}`U3E9>o9PKD@n5mmVq3gbI z#!SwTm`(PK3Qv>VZrgrdY%n$V!QI!<2GP#Gj18C9UaOyTzr4iv$g`t=4Hkv7ox0>C zApWYcAZTNQ=G0UE{7b(Y%T7I`(9Uoov0%pO|L0X0jApEI+t?6%_$K3qyWI!Z{aAQF zKwfp`gS8pLb6#h3Y`r6Y(WQL*0^{QkEI5j?)uIn?KJ?+>8(l@U-N_^+2*dQU| zW6&~jVeLwFai#-q?z#7i85_FSy^>wYaIDBX$mFHn+$mEIzCAT_ii@|_`~@pEU361! zp8Ri0%qcF|^j^QW&?Rt+^{%7U3#|^${{3(6jt?Py=8g*%RJptC zoGAFBJeZ?FgstIaN`uHsE~EGFPw(76(|Lz%_T>Vd1&8#5?k$;`FT%TG-@WrFLcnZ8dZ^Kvz5Y&jR>B{o${;l+vHGfwr+(YSb2e50Gi zscO5!_3`~C2YwnbzvXcJSp%nR`bb2XNSM=liXxg^q{?cBUUul=jwF>!UT%LSDc z!so6{P0o&CIA*wF&a*}RoHoh}=D1CFXDts;iMXYaJV%v5!|1w`(bq>uc@!owc&acQ z+TnVBI$QSo)!&X4Gd9d#_v$W(vuVnV%nQe}H%(l8cGf<%wXwpjVNpDPwiw=VTYbVOT?YD9JR=MPINmS*Y_0mce zr@~d3w^{spQ=z5SxiVRcae|iaEstGu{$!lV)jaI|x;?RS^?&>Ozy50N&!3(+Woqw? z8`kVw=N_IY_pnpr*)zeK^%6!NSv%y5GL~BYsnyf&Y+dtIT!3dMi@RC8`045y?{Zr% zGgi$wEZMm4;T@%8Z5Nga1kZV__xSZ(*$o@#w8s|w$t_Ix<6OEcDSMfC*|c9t2F4Ao zJ?+~zeAqJW@Y>Un#WUQmNgnNq5<{a)haD4*91HDJjnHbVzzrMGUTDf@hPN`itGZt8{-8*5Qee0FWt@o=h zz54x8$^Cama-6&JnqH%WZ#cZ)Wj$;=Zjx7j?g>v#mu21rvHPcuk7U2xWifS8_ve{a zGbA$_4$3WK>E?{{R519orBHWvt4e+GQ3V%@5XQ{bKy@P z{a~h@tY@z?3)bCZ=`a_HEb8U|=2XA~p(nJU#B+bJWT~ z-sphBt|p;%wOzcyj>i%Vb@*IoyxgR>;BeDiwwRKTo6jov;@4HZy3bnpPyecq@YAqa zE0!PSW=NWmSE4G>_R)!LcgCh;>$`V8d=_!WaMdxDc%N63dW!S(cHB8DoIf?{@n*SY zKlYsBNEg~txM8whSxaU@>;^SI_1BNy3fab-xp;K8>#rYME-}oXCY@L&@SDr#SZLG6 zOMUkw!bE!3UTw5_<@#r%`q~TK3?G&}tyaEuzyGLo{So#bi-R*1Cf)S)NiUly`l4@> zguThMW62L^c)f|Z*b^GECxq!JuZO@7u2g2x-PLaud~$W1;y1Zw>ioC6!#?+fMPOiK zNAH8Q>jw2IEx#0duTMG~W8Z#VVUoA_WakY_4AfSpvu-Y*BYyhCx{L(DYy;iu8QWQ< zYzXmvk2OP6dnC+M-ao5>Bjpd@*rS^-?0{`EhKf5^R-o~pR zW%k|qdUZda$u);2&6o3^U;Xm1{o8^^!6z9Wwa=PkdhyLEiG~;R4$4|yt`G<=o?fxW zukV2BJeIQb4fgw_9`r?vPTMgfvqgBNm4(#zkcatCF23UC{ZQAccyGPo!Ply7JMLT+ z*uLxY`&GRcg-*#HTk@%swQk0ll@C5u%-ecA$B`k>V|5SjhssrdCM2k|e!6fxfUQ9G z@C3h?GIC9O3O2bWam?DiEaBshyc;`n6s`q6bk{6$>L_82U%cmt-u->Nx-+iEbS-=2 zQj)4Q?YbsM=0(Sj{+As)UKkuH<8kA$SJ$&>nE$lWA_O`({~cD4$rljy!VX3;mZ=MUnreFp85E#lI@=G%$D1>z8~^tGOn8_*zanP zt7g6D&GP1%YZhMlTr#z?({aY>D+cY?r=OpZpwQp9@=HpGG^TlPjW18Zg+m-swc_5oC8<6Eo&sMA zE*)o>SGHB_G^_P1C4*82!)YIGTz&mUs?I=D?0z5rvG%{Q1%4Oit!uCC>|woBQeYg; zpD)Pp-au`~-LnGb-Cqk^*F8L|#9VVbrT2DiuB3ZJV$u@Rdzu@L`OQ0W@km+T^*+Zf z9~h3XwJU1sFs&54=+XVArRPP&lH&?y>V{}i!&kZ z2K9AQW)F$@DZ$I4DF*oY4 zJ*Oi1_-zUIooAj>z90Xc;NebMCDyd0gCi=_W>fOyiE|HV#T7|$T`~@sHL-Ku%ghyi z-mdo#`S`pEZt6Auo%H<=W5vp=uUdbxvP|N8mt_6z#J7t!dsgx#S4~~C&_dd__|nC- z#cHQEZ=UFX(&wy0mY3F~$CD>IZ8$nH(dwdZ%Eh}+E`*jWek3l$P`uNzEP9EmpYiKT z?c*HgmG$q{G9G!U=k5_(-R!MtWg)uKF?>a9|7xBOwe`w15snWo3w&EDl~g)IF3fFa zqH4ESvGESWW!X0Vik#2ZFfX4Rp(rbKh)tULTv1xoOrOJ(U;HnQkP%Yw2sP+9^Tt>F zLEeI$Z!K5EyQ-dWc6Dupi>7ZDJNCoiL-9pNq05K#N;ntqE#26*@BiLs z32&t18#en~O?mQ)S{H3r}yV>Wm{>vaX)6l8LhtQBV647_dKuVG>i9%tDz5A4`vy z`5rj8^K8V;pmx>2l^rg*tZk*M4>Y{ux-wL%Sc2Loy-^=0p79Acv{iCl0?|%GtD5}PCrS`hM6-TEv?ydOZWt;Y8?ZG+!zTPn2 zCiq;u=Rj|6@W+3D)Q&p5Sb0q(U>`U0oD|l#ryjoik@7la&)y1=bN-S&cNfpvkW#=b z#`Eg%_t%}gf3*s>buPa9w`;?4cd_#K%ND0s39+T9DH$uV1lH~AvOCxsR9#~?_4+<7 zufn_huX{f%xXIKXrBm2%Umuv&uzJt)>nAE6{okK$bh!Cp+K(mME&ZlPJWN?CeJ_vi z@b1Mz1-XT+@1B-~@T~ok6kuyH`}P~lB|&F*D9wy?lqvq-crGP*T34|ozltEk!l1RO zVh_?6-F?23LE(}|Y3wA=YLTeb3y%fL{+(+Qx$o+s3VvOl!mBQ_ju#It_TH9e_2AKg zj5TuuI>oGmUDyBhT~_pd{jQ&UAtj@>+@f|`A6oyJX>M0dg7@!{62XH78};=R}B5JW+jt) zcGt$W*?PyGswwN-;NQE`{Xxk**?p4ICtj;@xLMkyZtmp!k-A2=PA;?4I`kKd?PGbi zgYzf7&Aa~T%%dXjnAPP6SKqOz+NvtHJ?;6!#iF4Wh6dtmo-HtMw`u!w_GxC4Oit&+ zI`??7b2F-@Z}u>mU^`tZj6*x446WS*~rbk>(ULEEOxFGs9x2)VM;m|--m~iO*|*sD_D%0-K{#K?7@ubTG|0we+){s=JPyQ*&4}sYlhs4W>wiz!~W%&Z&vUe zzGayDB79ztPTY57iayZjDB)ycFvvb`ud!v7U*joGHaMQjW+siBp zviR!kc1zgLiD_bA{`~R7kCH!%UQ6uRoT8DpUcTvlfB)g76GgdRPfrw(4HZmWMm?&&L1V$WA5DCFEM}L7J>Kq^LlS~j1%EH_fBE-15p4xXvSR+(t`UEl6y?&m9|x~V*ywR(J>b>3gL9p z*>&;!{NIX)3afpX-szq`$SkM+`?R+2j{OV7#3LK$oXcLd^hnSr3x{1f31WQLex9^?S9Y#&?;;tSi&S#9Ce@#%{5@rZV&KQ?I;csp-v}&0YuJYHDPNG9EHxdgvA_ zW_SN$kM-==7P7%^r(gBV7gu}u{H9@r$#!8my`JNTkIvz_HIw(v;!@dHr`WvN_RSS) zj~81y>7D1#^?Ym<+wM;e{raOc*jVn3T>JfVXV~xEYr22$ZsUEsI?f+&6h0ix`}6CT zQ_bH`EHxWaP3)`<8oA@veOPY9_l@zXnJb&~{D5;Zv)i+8t3SNf_VGu?@tm5X0?Bv# zcCp@%z1y1~ce_#FZ{6YT>=swIQT~t3PO1C++RK7AZ&<1`ZFxg`LcN}& z?TOwqt_GhCG}iPSS$tD*hrKFGyl>YL^UFdRZ!>=sr0Lnk2K80nu70?Evu?$i%iixc zAOC2ye(A&@zlWQXC-{g-9A>)O_>5)F%ZH6uJDm)PR{0i)vDdqK(u~w43=fkBVCi%Y0bY?{yWIFaM zBX^FD;qlPC(tj0xY-PHu+|}c11Y7$&6kDfAozh`?XexK*$Ir%xKeGIl-{r4A>_2-| zVRV${&ATh}0PE@DXI`^5{`=*x^61;p?B1 zKYwKCZ|{6R^W@}H(;gq(dbi@wMb8J_#T9>Edj6>@=C7+QR+ihlO`^Zg_vmBhJ zHU22_%dat7D%H;R>|wzBls$Gvg8b8jj=a9q;5(=I&V*L>)0+#*UG3iGzUqqSyY}$k zMYWp!%Q?TRg+0)FuCOmrHQ##uLi?q&l(x**XLxZz?l9Z*Pk)}&ym>12J-njsKvRVC z6|2_?a%<~TSFj!1WnX&OR`$xyyMD5TEDh@y{+jiCQB9?AdF)s5re2f&BeOF$u>ASb z+*X}gu*_F@^^EiH6Ew?ZQ z^=5~NsFQDRIC~X_r6d^M%g{SiuIpN1ut{Qn@8bFL_gVWZkNi4(bnl1L69s>~+X%#V*T={7m>Rt53wn79S{6hw{wd(uu~~S>Rwn*Donzl+xF!}B z+~hA<9=b1&^}tf&?hijF&iwJ?LCl@qJ2?IG}Xb^c=7G8IZxK~n;&|3?pnoCqlV>mPaZtI7|O-)Atjl0F6XAH zm*(1ccVr9Lt4}%ZSaxQC&XP4tJuau|yT1B*UE_X0-LpNn!*#mvCFcJ3F8d%?C=#{t zsCM7l8&mImsZ165z$?0MIphA^mB$}j|8D5#=(Cpo_~2aCp9>KS7#iMi|5z0IZY$#f zbM@zsZZ)b_{6A!7^XrZ1gX855_w9}}=l>|yvS0qUK3B8)(}z4K;FRdc*H4*Q!UrtdkJuO zcU|OpGp%js<<|yF)3wx={8*qK{b;9+x<+q~;f%|U#gRR;-|0!tU~pg#z2a>a{8d7D z>;0M%>m#<|3_D(|3NJ}&nVGe&Ps`|l1AnQH;@>q%$?4IP^vr}99#^jV`pTmC&C6G< z%+8MrXCz7DD#f83jBq%_2xV@Y^ln-m!O{$-YMBmDwj4Sh)^# ze44tk;SJBE`>|HLIr`U~J-*yM{o%KhUw=G(cKX2f=O17E%l`50mBod2#>^=UUH|GC z9V>O2bZ(|=G%jVCIVsa)b!5%2Ixfq|LjPh-V@;taog4}*9L*YEMG{Zh&0V}9rLO+W zlatRLTd^;kborQ}k^I5f@SraI=v?jUkwbR*(NE24Sb>y?`0 zY?hq;K_cCGZiN?FKS|_nFHvKVYIvJ`z&O4!Q}ajT+AHtx#dWK{*EzcQ^yW&QyCyXz zD_HD5_ULov;b}v;EcO>`I57-V=S73q^bMJ4SdL_1TJO+H)^nyW|5)`+Y}+9`ys_%n4WB z4t9yok&M~3fzddEIU-iD$<=1Xs=o7r91kZ4I9ZlkhOp(`teSu7Oa7GIVo@u)>(*uI zux*TYX5%mjuzkAb>cgLMqKnsG+c$Un!egsv@-Us23BA~^mte5?d}ZLR8z+L^g_#*| zJN_a;aklJiA>YD1N95FhwI*nPf07@6gWH=c>BIspuIUPleH$7Z8iKpI7&v&(g+2Ve za!*I=y=jO z|Ni88_Ph2l#m}43Zq2Ut@Yp_13-e7uff0gFPyFuuuZd~bGJU@VUukA zwra&wcD`f*Bjv74h3en0AKg6VbK&SYi&&lRE64rJ^7^J)B$xXdgng>n*IS(R;ZsZ2 zmuEVOR{0@WEKT3))|%^gD;%6)&~Sv|(q{43_dO=Qh>$Yhv>+*Ue?Y=ouD-)ToNMGu z(l&Oa3nohhADb9@=Cp8wj_;onyrS|k5l!pk=eEkn&uv-X*L(Eq%B@|I3@e%97J7t! zsO@Ta^kib>jx%i+mPfN2u8?M%GqXp2XXMxBa+;lYo$6*S62oRzZ~f*)J597=5KJ;U^E^WJJBXZGDE*s5<{u?Ws- z)V7^lxW|w~diLZE^K6^`djEb@lCZVjV8_;Nn!xih?>G<0BU<((CeB z8B*jN?giIuHfeV8Oy~1G-u$>kUR=T>PVT%&iPgUSM$-B7;+xdhh@7fE{^$IsqnE?(dgqo+7elSd(nhc8Z}W_2K0E30>ri2A#g!VN zzN@ScSmbAHH9yDl+Ih!5ogH73&Zn+g&1d#$b9h@uLgWOIhb9;2&%ODso%PqWiv9A|EzB_mbDb64*)|87*tP2|WJ{M+s5=;_{;~J5hLA{?w}662iH@G5 zn3q!eLchN4S_}$03f*gZ?uc$|(04o#>`)P6Sz#sIY!bBj&%94Zx9&V39sJ=%4fj6# zyN4$4mKL4AbF$L?)>M}p=0`i3gB!NHF~9%#yO*c4V~YN6O``^-E&7`GS+r_3%FXm2)I4J2Texn{ZDDP-DG6sc zgyg)FZ%nRnyA*BOw<9c}ZSR`(I!k8H_2`m6JL$KR{IN)rT|5896mL49B428-)yRi31`iMN>2&KoOL$Rr>SLI|iKgzOnj)W-T6+cOtz?S0!T2Ux zL$vJq50_$49K<1h7rFCCQ51zG>u8GKQ-v1k4nB)iPeR*zS_XF`Z%YuSbfIdy>m1Emg)SPv2yX^g}1(&NxhBz*Y+wraO1U% z{BxH+Y(J^PU0xdYxS&a`{98t0NoSrypR;W27t2ej4com-E!om~zMm@n5XQ)EyUO>& z*#zl3vM-zXcRqj5b9vj_=ATp69t`<%!e`Cwu%@rZJ2gJ9+L&oL|KVY_^UqSh-q^Ov zeB1h$?Xs^ePaJ%9?&03#!o2qtcOGcU*H7Z&5-_P|HY;Jh_{aY6@&`YHjF=b?e6(A0 z@9Saq-%%oZt}_ceQoA@F&#|*$?AJG(obZrs`Rkj-3Jem~bM*cHtQU5*`MK|6&ZiYy zg7^GiX?VBb;h&m4MHNDEw+wl1oADjF_O8nJ8$0A=!b8$g!h~j`}jI%>ipAJk4N^MpWAWu z_-WZvi=gwTvR8waOU*J8Y}hVd+)tWYT(cE`RG~iU1NWR z&))Cj0e9oWAHVUO<38heg!S6-_@^&!bncvKv2Bk)dsykiLcOUKm4)JOW<__s-K_a} zSJLrIQhDz(4ouv;_-5L>_I8^rKas-tR<7!W`prg~JQEpJTpz!Gzb5;LFyjHiZ@hfh zA9shlKem`Je8eDfVz+jxLA~An`I=88%Ov_eC1;&ocHRBqwUwL}2VTaXloH81-f?K7 zPUZXKOFoxNCeN|55v<;Bns{BUsWjI=&;E6z?CM>gGc{s2mh&zC`Eu^Y{3I(sU(bWm zHoQ+SpG^EwSH(~__i^Lz#W^4AwhG>RmDOUN)mzvn9IRf%TQF_%<@aKRUAr7+&tKoT zSZ9aqc?ISc!xztH^{2kN?r=Xo=ku0t_a_?9o;GWh&xU_|@k?fYFmV3b{?bU{(Ym&U zcB^I_>W(>8b%4?D>pY*w2h?9PnR9I|+&*9M-B-gy?sIkn2>RxWHf zs>$iJR6+UWjEMbLRL-52Jhc8x%KL@0^qO-%owJaWH|K2M@i^?y?jNO{pIU!CHQslg z^2urH56_*+sIk za^v98@;nd-e@BW;lI>4u^LHuWG*jcx&Oz&6B1Z?W{X0GdFquQ&qNG)jPLkt7`CEP^dF8=-}PS zbuN9`tX0ZwpJ#oOdMoMtUv_`bRqG?arL$~AzJzYFxN@W-p=bh|nab+~b-_KIAz!n) z#O$=LA6_2&<%8<;NBiF9_MCsg_fG89!#c^<{q+&K9qLQ$E+`osZgrK3IuX?ul$)rx zzjsq}?AEUvWq20G$DjMzVEU&rnoI8enZy0RSADoRQSFYEiJM@rx0SlI-P7G)1XRB7 zJCl3gUiL+M^=s|I`9Bj#8msKhDRc*ZKP8A-tP+jIH%#C!EJ%}YQ;LbLE`T>F8d_s{#38f>KDUn zo!b)0Z#ym>xfM`)CiRK^waISj%e$CX{+9my#7y?;?69o2J^%V%)&B|%i^{rv^!t;U ztBdx}vf>t+HRG&IspamL(@l}GDMzYIoA>q1Ja~JJ;E5O4*?+qI*l~j6yCqZE{Dz7f z$3^ykO(|SzJ~M&E(V$z*sG0kirUIX2!Gb2!x}ys?7&o*uiwf`Tc$^aWm$M_~&z9xv zb{1w#@ta;Kb4|Ka7rxqKL-~wm4f))+z2(oRKivB>wlKY1d0SE5di($W5e_fnwI(t( zc(Z4mT)yImu@D2_f&3E2^dBvOC-16G6`uHgO4GUH8|!M$T~xTU|3uD1ndG+XH~v;n z)+vs?(Hwi`Z_3)UTmH?QlPPodO^Vij|IY{WmEV5I5LrH#J?i0fDdj&WYz5|*TzhD<7#Gw1`*TVN*7Z0U2J&-wlWVx`! z-J;|Z){-oaeTMrU+T6Lm*Q1%`pmNhg!**rE-fM>4SNCr0i?Nx>{^b0pT2|e9&CDs? zKbOq>$Sl9H$?{^wo`oFq-(??ZKf~qn(dj%B%gN76XOv9aU046;%Z0Hc2Zg7!~Wo4TQq;lW$M z*bgV|?4G`9O5w59SmPA8f282tAz%XV)xXk4)h3J`!xXXp7UfTEqHU&8Bq? zj%Os99%x*wRlF`DKfPFO-HhtT6`$`5veX~a>QLI!pSy#nv!mUPw zMwZ@g&;RS+%XO{ipQI_VBFT8_?kRP3qPlg`%cpI-T$;P+()CMob)T2MUm|_`IP)rV z0fx&b;+of37-#fUr!?e8YVSNfKmXZ8+0AQr8n#rc2={JOJH+F?<9Lzp9>r&qJ;mLM zR@bVi*Uw-K*~m3J`|P^;iS6oPQg6NgC!U(lZx)`P|9s{0D*cI94>D<+UfF1I<&fUP znrrM~n{#$f7O!12nJw;d*^0l4$0}NTd(AB@K5>5MsJnMs!v3r2LxUBn^L&;&Ef4r< zBw}@&(cZu4$ok1EU+irBkvYLwj%UO2N0Q2C6g1Md{kryYj$GXN!i}|iKb|{uuj}2y zh?ORjmo#a7*|*xJGtx!>*&Wv%Myn;vuU$Bkuz<}+?49!nhMTBD>--IY};lI`*}G>&K_3Y z_~WR!=(JUDc6R6AcVoB{by4`bx_H5Dks-|eTKkk%UOA{Ul|oXzrbK~?~vHXF9J4+F8_;#*VhWIt>$yIoIg!} zWA_Q0`enQ1exwQf{l~E{t;d+%^Xvz1<^RSGM!y7PQyv$lQa zX+4{>Nq5Otf1#(FC9m9WRj!1gKO~~W#NVk$o%8SEmD}9W5;;k9LeX`#$J77b{b+c3 z_tGt4FXcV@V}Eg9$`oO!Ibpb#fBBQ*GJXE|yfp{E+1>Fx@_+Kb-5nbmOElIOKjFFl zl1Laa zxTPeRzvArv4?7$BmsLG{ZTIcRhB=1(=52SL%AMGKxA$YFD6>PFYkpZ8r|n?|{m%)V zwt~leetwz3Qg~vT?X;sC@2J06ezdmf)rvG}yI#?Vc-v61+FQci|6Ss*MakB@*=k)Q zeRhkBl96i@ju{@m;vM2o@haIDcHj7GxW%NCQ*0vVwPlaC|GoR+=}Ww_&u?2N2LGv>xTv8i+=x3zav?*dW!X;$RCyF@%-r(1;@(f zscoA5n<+l2z0^4P(9|g_Cz_~91@XI{jpvEqP}kD=cb!-b^8f!jB%zafKuy?v zk-@^;pOvbNA1HR#B0u|x8IY0+naxE$3r)H?>SF*vd`XO`p@F_v;2+4Rcno78M6P0Pl|BpzHn45 z=wDvn&9%K(pGkH_Wjy)UEw|1@i|xi-pU}kBH~&Qk_wubfADn;w?cOgT@j3ZxF4isH z?8ol1*)BF^bzj|@h~AVmgWkLZS>vX+cVw$gLdEl^zJ46Wt9(E2*pD63+nYCs{Lza( zG5@+`@K3fMGoL;_zWB^XXJO{0``Riju88z6zjP?g$Y6>?c3+NEYRKMB!S5Tr#8TRf zg1-d!%=(|qMyTw1=#D0cqa zhWVSq-1bJg&vbceZa8h#qiwr&mfbkmvvG~7^#O;i%;|2SaT!yeFWde9wX~-G3s>i@ zWy^Xv<33+h=h(5>V!kuirA;!PQnSy-lo>M5UTXO3#-Y0hX1{!0R%m}P)68n!1*Llr z`fm11h}0eY@?y8$u^)bSoZ^$yxZkLlNjbl3K=RW;E^6rtoj{pAq*Qc&r%c&>wIqD<>|8eVw z2Sa|<=W*`7p42VRCM=-*=ELCt?wY9cY5sk7ekm_MIcPYqQ9gQp@zM25E?sXgzR+&SQ&7KX8KQTGM*W0+h@rU)GAfx%1UgzOejlhS@Kro~+p|mX|*3Ok#WFlAWb@;>zrN zyV+eY{NJ4ZL9+O9w2k4Dzwg{C_TG`mFMPel#AjdH9);V-o7 zyDP87N3BjuT^E-ouw97Z{wK|+{b}h1&FMn#^t6sCz7y}s4BZp4pFv^Pr(FyW1l&(v z7h>3by72pvgfnUkE-xQxv4k*f@HXD{`Qx^!Kgtq$?6L}uW&gC{Slr|Oz+~5hdmiCz zwRgBJu1@4KKgwQ``CjdWk$Ls^FMCd2*Y)Mx+pmW!x^8`Nusy>uNzVR!?1D?x zMb|?ou4VK89rQeBzSJ6%D+^aIV~f4Yw|nP}sF?Utul6v36Azx-_wd$j|8=cctIm6dCLu2A{H*oZRGpT;=iasj4*zrOMB(=P#>sdbugzvCMGq z$zECi8%D>r)%@ADx@XO$4pttW)Cr*ss(Q|K`_47?{l2|pZEl#zzTCot%kS=B-gSsk z{^Q2?@t-*#e6Lt=^sXB>-;oX9FJ2aq4=IwanW-0-YF%!=w#HhsE_I7u+NJ0IJr@p( z@XhFXG$CD=al+}B^ECL%KU9dHP_F8^dUe6_YY%mMzv=%fh~?GXCF0w4%U+1X>uLAZ z?nh6Po-BIus7F&w#9DZ3*;XI^`jYfpLMQq{Wi;2Gn8)y-x9o94a&NO*TfwSQo6W2< z^CZv6uJev~V{z)!N7G%+*>BY36nx*Exp4eymYl)W*;9@AX8tibBI6&SeIP~JCelId z#HUSuwOqheM|nSbcRosz83;tf7n*FTU>JUDvRJ8jkL867ao?MWC_tcw5Q(O ztRn1Z($}DFv653qZw9J(eO=ljxq7R#{>;Y7>$GaVToue;)28!m)6F|aZ_T_tTl?u5 z#d|*jHXY*d+i_-D_l;AJE+!fstX$SveM9c!c)S zblShu?>Y2+_o>3vD)Uy=?)T^OLSF@bV|uqYrn}lZ(r}Jozx?#)k4~LSb1~XA{W>Ru z%gRZtF>!b0#>%C<{HI)SnVnxPnOF9mT2!))wU$bGOeO*j^LqGek;-=%% zuAM!(d|k?ND^8Z&!uEsrs%1XyaNPctjlbFI^tpS2Z2Q_LZ!PH9cwX|J~=ENNG@Ybp)mt}RfUViuC!ej-GXN{95ZmONRJmTkv z4=-8d?8DFKrZ=DD*!y&n(Y0aRn2wy+i=-7zx?9SQn8(SpGCG9C;ff%e*d9hN3#O`rzXpe z?%i=zZ>syQvPXa2KiSCp&pVcP+9>6QEwt}2KEKY{l40Z|BPj1|@Z?j(WXCQ4EbkO%Z^*i z9N%SO)3>}e<)Kh*t<-!;h4qsy9OAU~9^AN7wdefXTkp@GI5fSR>%-T7bvL{iPWciZG`_BIZ5S9*WHJ^lCX503s$zmG|+y72nKzs=wD_Z+y^%(eQe zmXAY7L|s54$07zMPS4gGVIP;DU|1nB?+lZM$Ao&dttYioTu4${PNE zGENH>R~Gn&rkMGPoZq&at2;xh=?Uj8*|Uf*CiFR$@&n*PRuP4j>A>y>Ui63tvw zDdds9XJ@*Bk;Q)fE}>h~JmP0LzF+sQ@B6alkEHmQ?yxfLPQF+BBS+CLu;stL^{nxWS9zM7D~+o{hx{=YKx$i5H#E5|^_yVcF%9 z@ZTP9^*48I?>~4?abDdwuYC>Ej_)b@O){eDcAHJ+keO|l*{glsMBbDy>i2^RoA*xO~X=6TAx;mPJ13|(X@P1z}KVV z+aj{I{66Hq-ByYB#-%3?&Kk{flG&3OJoqeDBr~p@#C>I|`lQm0*PQZ~O-TN0VkvOs zR)s`sF~ z_H0*S58wX9jZ@xQy)HgZ-AAEer_EY+ySTW<{^jWp?|ovbsa_$^_kkrak$vgx7iZO% z-??+|Kv$vAw&yzvjn`-{-@BzU_STHEN!OL~9!5ES-@0S5TKkMAEd0EFO)HDd*NYrY z$+qRc{bb#;nliuO%2!@f6svzl$tF17y8iycyS3tR0g-1*AN^?LT7EU;S-_2ski_KR z*3a5nIj$=<$SgecYwDp3Nt#SdiA;s;zeG5XP0f5%yjoDBw(HWb)?ca*CZ7n=bI_Up zE~ItkCNJjJ&0<~MVOsNetwhhIuUNBSjndv+!{Ge#+ku;HW44}PyS3`h>4j|q^KwM} zqs~0$dy*8@E>j-l%J#yM;mb3z6_PSWGmroMuxW+2WszBH>?TcF-;J9N2uDi^7v{Le zhZy7vALZWKeJO4!_m6~P-n$Oz^W>+T`rN#!ptw9=ZqJEkxoAhF9z~sk%q;$04PG@S zy*wLq+_i- zY+)a&jOJ#iFy^pWSM<)A`R1V2KAH8wDJ#2V{63|8yt38r*V~8Q&IOmU{zt4o+&#xK zG}1XzH`^sKJ$hprx2Bf@hcd@vE@=bf(1wP>^N=g|qF*p zw~;9grma6}%H?GggEeAX_tcfFvG>zkaqwK+MjPQ1lA90lR9-UgKa>15k0CZpJbIHD zcl^~oWtN+kiW|@Iy63G{{9A{~dRps7gD_9)ppS89`gE?|u3dfgU2Ad-f1lKjPF>AkB83;vn~G(4{};;fSf}5? zy`bZ(v1{1Gl_8GHV;WB%Hq*2G*MF55Il*%g3Y_nAUi3{{cd|>zaVFC#hZ8q9POYepRDG9wBK`6T zp80QI_6FNb3zKk~8S10)jCsNG@Wjegm9!5bTRIhs9$EGmBp0Y3UAu10qtFQ(PpMpZ zT&foI@#GZ0lx-Yr`|Eg`Voy|UlX^Q}V&&G|SKqNteH+8iXZZK!t`GOU3^W=QdKB1H z6$I2WmU$F-tkI5e*rd;S?5M@mJcmf>2kZak$De0%C<;*Tda`WNJPx7OX-E7!&kOxm z6<-tbZ*$jl>3^|5p3OGBwY|PsbbY+)|EWTo`q#-6FFLpPos`XohU)t-_`Gh4XfAxe z=GmcXMs_DQUUjmX??2-#yG73<+LGAHsv@UQChGRWUvRO=<0%qvcOGN(V(7>h zWD{WM_&@zbe2`t|uit?xx90l^F5zMb3l=Hy54?9}zQ+Eyz1!TumVzqshLpSh$S6%=Gi9{c!4ma#!2yvzO4o67A=S@PGfJM?wt%^l|+ zPF$T`wW&dPRRSmD)D-5`Kh89MRpzS9a#vtunX$O7Zl71+qi5xEx2L&_bu8!RP|UD2 z>vwQ2-EnE}%uTD7FJJeoyXtq@_4t~Ht#j)gf1cmexMr@w3W>=(g8S68j9L<>RCO^p zFcl;|-fzjE!YshxvEiY|M23JyTVswrrQ`bv=*^)Qo_KeoX%zHK>mv}_i#FZ&>c-^?-l|IvY)+zp^ zh28G2K6J`v6f2>FUd-@!?{x?uTBS-6$_+cSt;qcoI6aO*@HFzuN zU3K(4&8rc#P&C%|x`YEKL#M%4O`*bFflJsF3L7>wurvj2k?@}BCAg)_I$%@dg&78i z>e<`2HQYE-^~2NlYFYW4tyVVAWNcz)nng_zT~l&`g)OS1#Ngp!MVkxVjj{J{<+LvK zs*nHl`(e$8Pm=_X&Ipq8yY=nZl0OVu=AywBIF0f(Oz~q-u9n|4nf+)l!`7?sJ{U9a z`F{1qrHb|EckM|R{g?AaKl`%Thv-A~-fRZlO8erc=(njcE{L$#_gC#u(u)i#_PjVX zvcahKIjG1xWj={(vJszvxq^;^bC5#7tA9b;#RN{Uo@(U^<&@Uwau8u`S`Zm?cymI9 zS=f(yu`ceahT7KXV_9$OO{PxL{HrCO!^>|hH~F0V_NkvfZrED$Y59+`m)|<`-{&4# zcq%SaVwQBnL7VjajAiD>!pjeNyi-=F64g2I$CI(a^Nzm3qI9FGk0tMZtr6gPd5GQj zgQmhH#gI(MgKt`W_gC!M-aF<^ap#mCmWd-mH0 zmE68>oBh&j>FHY?>+82ks7&0y;|5!oM!b=Jn?aXIfY!!I)4bUf7#HlwN;REeZ#RGa zwyg{cC2YGC{5CNbvi3|AQJAp6h0AG@D2KGhsRJS>`O<=qm}+o4=N{ZJYk&S}zWvv^ zfBd$OJR=?-aC6zQJCU1fcW*ZdwXR9`JN@OE*~bdIw!JQLKaRNhr`x&d_NG2OS2H82 zG)+Tm@sAVN6{JNz>^!{GlkvqxRnCvoj@2-!|L^mEu9L*LQhdH%)XkmBMvM1MynT^( zYRxx)eY;Jn{qN_Vy}qn4x-v{%|Hy~PgZFHf-SrHAYcBk?tbB{rmfcE>I^r3ZH(x(h z-@WLzR`fgX%%?@?7ZrSbzo=wmnW2cG#KwwL%ZM!PN#8u@sBY004G*;2xX!?#x=SJ@ z`gMKYm-F94Yqq8`I?iB`dX&F}WhD#a%y2;wFCT@Oj=Zj$m>HYywCrHhqUGo)X}elFUwLs;_3CxfZeW*rQ+ zy0oKN{qVV_{<1>HDXUqTeng1IYgtY4m+Ufs3e;=;Rjaq}k~njcye z?Rwhw#9ofqnxgC0d^x$7`>6I*y*8tXN*kvvsS5fhdbB&RbGGPw{ml70;y(WVCSvGf z=&|&D{kv=DzlYUmMmntWdBoL{_eJxWh^OO|rX^+yjSH8wSBk6@^k~p9H*8S4xZ1>m zg{Nq-khaIkh)1l9Ejn!mEfI(18=b@oOOE zy!G7Be>hp(`g8lVXKnVgq+i!2r?30Jb93*><9dA0w$G8#iQB%_&^9wKZG(4sc=6&@ zS=Eg58-g;=o_akoJ6J1fif&il>Kw*B8y0BPl)c{Dy_DO#>(bGHBMDL(lb(kMAKB`4 zGrY(9j_zSG*FUPQ@*8Uc_erEgzY>rA>$`6rYh%rZn1+~+ABvoAOSDuuL=`+5G{p7S zEo@R+vw)@f&WazVg~E>>vj}XGI3(cI=oN6HNpq$XC(lBkqmP0FwK5a z73L1tis^AkQr%dxutIZb_obr=r!*fuKl(`Zytugb!Fduh4c3XecG)@oPWtKf)V}=H z^XmWh@m>NPS5L5?X7vzuY7$6f=H!djU}8yRaa?<0+7XUNax6TtnnjC+OuY77@DOx3 zk;LKLvrNNL@#1=&IR>pdk8-+nRzyr}aORxQ8gfSIRFYPvXFK29>0KY5r~bJcwDd#y z=_^;Pbe21X2ZROf)P9<-RkQQY{7@5mxk72axVQLrO)v3gLAKtd9nri?G(`2?(!2z}Ynw`T z{;&>k5w912`ngynKG#t}TtUzAhJ%1+DHCH;z?21{diUlltvPTdnvrei!JIA@6Q{yM ze2<=|7`7;?lnDf!a5~w<8LZK$*sb|sLhDpkv2G#32`3J52TVy2Z0$IcCmMJuUis8@ z?f-F8R@KD+lv%3EZ86nrTDFjsxSOym_YC&nBmLc*SYISP+$s{dBVwmS^Nv$KT^mw$ zTzS-5ln$Cs7ID4kTU7J$Yf{RlW1FsRdgk@C+wNc5mh<2L9oB!^&h<-0Z$h`Ai&u_< zxTd&vhUl(M%Q>_)4l0;SI40h8b1Yo5P3wi9#G($Rjm-^CVqTZz61f=Lbds1|Ir$QK z89Q{gHMoeyWrU`btnLV6G0AnE^40y*o7YeBpVqpp{4|frX=zdWwz_RG%^H#GJTqd} zZJei+FfDuiq7JZ=i~1K87%~~M8FF>LXno}Ra?-U2IXMiKC}nUk4wF=WJr-DM~)X)0F3#{6~|CW1)3qk3|=Y%_fIU0ZyHV zM3{IYT^4#Vx{JC-IEzKD@p4cSQ*#i^5_RR6+!5p=73I3-qkiWezn|t_t*5F_{_aY8 zYW!sL6XU0wpGrN6I-S?RlyL;una`*5v0^X;nxV>FXq9-1{x#8Adi zp>uu9tD|SPZLLUM@}EE0X8m*jee+nGVisI7<3+Ps6qaqEKU6=&xuHB4|7XcN%p zSm5zTp_Ol;3#Uf1Ca1{B##G1D#8y)lg``j>p_P4{0WDFkf=m*DT^$VWE+F@PDm}G- z^7jefCw&(=dMf=y`pNWD>8DLSYLu_591vaIx0GWB>y<~pj_mrY$yBkiU}yNwbWlhZ z&fKJyJ5?`REnB_t+UB}{@=ibZ^!@*~T34WD-mOhd3K5)aj$3zd)^-UAY~t7?A@t(L zcD)HZctO$1GIdjjkO-$mN@8l`(WxDwoE}G(9tm>cR7xsUS|q`EE?)anmEg~4#<_c@ z8%*A_y{1ni+%DKIdQIfY6vlP(t|GeEbzaW8urp%2M)W&hotPT|D+_A>>0~Qre_C_t z=+!JpFweo`aeHTu1JkUE>(jRL0OF?+f5siJedSG zYDE@ARxoyL=+HQ{Kh(uA*VW+*C}~Zp*MG0B^nQKFx|(Gg5$haRrd0paG0{7t)+H9e zJ-3@%57=8;l!|5B(Sf8;e~$Zr_$X2VfVc61-sZeyVwPbtl5&bQ;%_7 z%wjuNk+oaiY&#_;7V@ijVcF8D|0iDhpIKwG{`1ZnTW&U0YYoXox*AgqTPA5vdFOmU zk^7dI!lnzG9&GxcVx`R$KCF~4a zx@hXOzwW2uhTec^Ypqtk5jpVdA0NHf34ZZ z^{?3L-~Y9x_WBNgp4a}{%=AC9@&B3w^ + #include + #include ++#include + + #ifndef __WIN32__ + #include +-#include ++//#include + #include + #include + #include +diff -ru orig/source/vid_sdl.c source/vid_sdl.c +--- orig/source/vid_sdl.c 2010-09-06 15:26:04.000000000 -0400 ++++ source/vid_sdl.c 2011-02-09 07:21:04.000000000 -0500 +@@ -1,10 +1,10 @@ + // vid_sdl.h -- sdl video driver +- +-#include +-#include +-#include +-#include +-#include ++ ++#include ++//#include ++#include ++#include ++#include + #include + #include "quakedef.h" + #include "d_local.h" +@@ -81,13 +81,13 @@ + int handle = -1; + + TTF_Init(); +- gTTFFont = TTF_OpenFont("q_sys/gfx/dpquake.ttf", 12); ++ gTTFFont = TTF_OpenFont("q_sys/gfx/dpquake.ttf", 16); + + // Load the SDL library + if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) != 0) + Sys_Error("VID: Couldn't load SDL: %s", SDL_GetError()); + +- if (!(hwscreen = SDL_SetVideoMode(320, 240, 32, SDL_SWSURFACE|SDL_ASYNCBLIT|SDL_ANYFORMAT|SDL_HWPALETTE))) ++ if (!(hwscreen = SDL_SetVideoMode(480, 320, 32, SDL_SWSURFACE|SDL_ASYNCBLIT|SDL_ANYFORMAT|SDL_HWPALETTE))) + Sys_Error("VID: Couldn't set video mode: %s\n", SDL_GetError()); + + // Background +@@ -208,8 +208,8 @@ + case SDLK_LCTRL: + if(option == 2) { + // Set up display mode (width and height) +- vid.width = 320; +- vid.height = 240; ++ vid.width = 480; ++ vid.height = 320; + + if ((pnum=COM_CheckParm("-winsize"))) { + if (pnum >= com_argc-2) diff --git a/project/jni/application/quake/source/FixedPointMath.c b/project/jni/application/quake/source/FixedPointMath.c new file mode 100644 index 000000000..78770bfb5 --- /dev/null +++ b/project/jni/application/quake/source/FixedPointMath.c @@ -0,0 +1,344 @@ +//Fixed Point Math Routines +//Copyright 2/2/01 Dan East +#include "quakedef.h" +#include "FixedPointMath.h" +#include + +#if defined(DEBUG)&&defined(_X86_) +#include "windows.h" +#define FPM_VALIDATE +#endif + + fixedpoint_t fpm_FromFloat(double f) { + +# if defined(DEBUG)&&defined(FPM_VALIDATE) + fixedpoint_t fxp=(fixedpoint_t) (f*65536.0); + if (f) ASSERT(fxp); +# endif + + return (fixedpoint_t) (f*65536.0); +} + + +float fpm_ToFloat(fixedpoint_t fxp) { + return (float)(fxp/65536.0); +} + +fixedpoint_t fpm_FromLong(long l) { +# if defined(DEBUG)&&defined(FPM_VALIDATE) + if (l>0) ASSERT((l<<16)>0); + else if (l<0) ASSERT((l<<16)<0); +# endif + + return l<<16; +} + + long fpm_ToLong(fixedpoint_t fxp) { + if (fxp<0) + return -((long)((fxp^0xffffffff)>>16)+1); + else + return (fxp>>16)&0x0000ffff; +} + + fixedpoint_t fpm_Add(fixedpoint_t fxp1, fixedpoint_t fxp2) { +# if defined(DEBUG)&&defined(FPM_VALIDATE) + if (fxp1>0&&fxp2>0) ASSERT((fxp1+fxp2)>0); + if (fxp1<0&&fxp2<0) ASSERT((fxp1+fxp2)<0); +# endif + + return fxp1+fxp2; +} + + fixedpoint_t fpm_Add3(fixedpoint_t fxp1, fixedpoint_t fxp2, fixedpoint_t fxp3) { + return fxp1+fxp2+fxp3; +} +/* + fixedpoint_t fpm_Inc(fixedpoint_t fxp) { + return fxp=fxp+FPM_FROMLONG(1); +} +*/ + fixedpoint_t fpm_Sub(fixedpoint_t fxp1, fixedpoint_t fxp2) { + return fxp1-fxp2; +} +/* + fixedpoint_t fpm_Dec(fixedpoint_t &fxp) { + return fxp=fxp-FPM_FROMLONG(1); +} +*/ +fixedpoint_t fpm_Mul(fixedpoint_t fxp1, fixedpoint_t fxp2) { + __int64 tmp=fxp1; + +# if defined(DEBUG)&&defined(FPM_VALIDATE) + fixedpoint_t fxp; + tmp*=fxp2; + fxp=(fixedpoint_t)(tmp>>16); + if (fxp1&&fxp2) { +/* + //Dan: Temp hack + if (!fxp) { + if ((fxp1>0&&fxp2>0)||(fxp1<0&&fxp2<0)) fxp=1; + else fxp=-1; + return fxp; + } +*/ + ASSERT(fxp); + if ((fxp1>0&&fxp2>0)||(fxp1<0&&fxp2<0)) ASSERT(fxp>0); + else ASSERT(fxp<0); + } + return fxp; +# endif + + tmp*=fxp2; + + return (fixedpoint_t)(tmp>>16); +} + + fixedpoint_t fpm_Div(fixedpoint_t fxp1, fixedpoint_t fxp2) { + __int64 tmp=fxp1; +# if defined(DEBUG)&&defined(FPM_VALIDATE) + fixedpoint_t fxp; + + ASSERT(fxp2); + tmp<<=16; + fxp=(fixedpoint_t)(tmp/fxp2); + + if (fxp1) { +/* + //Dan: Temp hack + if (!fxp) { + if ((fxp1>0&&fxp2>0)||(fxp1<0&&fxp2<0)) fxp=1; + else fxp=-1; + return fxp; + } +*/ + ASSERT(fxp); + if ((fxp1>0&&fxp2>0)||(fxp1<0&&fxp2<0)) ASSERT(fxp>0); + else ASSERT(fxp<0); + } + + return fxp; +#endif + tmp<<=16; + return (fixedpoint_t)(tmp/fxp2); +} + + fixedpoint_t fpm_DivInt(fixedpoint_t fxp1, long l) { + return fxp1/l; +} + + fixedpoint_t fpm_Abs(fixedpoint_t fxp) { + return abs(fxp); +} + +//TODO: could be more efficient + fixedpoint_t fpm_Ceil(fixedpoint_t fxp) { + if (fxp&0x0000ffff) { + if (fxp<=0) return -(fixedpoint_t)((-fxp)&0xffff0000); + return (fxp&0xffff0000)+FPM_FROMLONGC(1); + } + return fxp; +} +//TODO: could be more efficient + fixedpoint_t fpm_Floor(fixedpoint_t fxp) { + if (fxp&0x0000ffff) { + if (fxp<0) return -(long)(((-fxp)&0xffff0000)+FPM_FROMLONGC(1)); + return fxp&0xffff0000; + } + return fxp; +} + +//TODO: Implement sqrt mathematically instead of converting to float and back + fixedpoint_t fpm_Sqrt(fixedpoint_t fxp) { + return fpm_FromFloat(sqrt(fpm_ToFloat(fxp))); +} + + fixedpoint_t fpm_Sqr(fixedpoint_t fxp) { + return fpm_Mul(fxp,fxp); +} + + fixedpoint_t fpm_Inv(fixedpoint_t fxp) { +# if defined(DEBUG)&&defined(FPM_VALIDATE) + ASSERT(fxp); +# endif + + return fpm_Div(FPM_FROMLONGC(1),fxp); +} + +//TODO: Calc trig functions (or lookup) instead of converting to float and back +//These take radians + fixedpoint_t fpm_Sin(fixedpoint_t fxp) { + return fpm_FromFloat(sin(fpm_ToFloat(fxp))); +} + fixedpoint_t fpm_Cos(fixedpoint_t fxp) { + return fpm_FromFloat(cos(fpm_ToFloat(fxp))); +} + fixedpoint_t fpm_Tan(fixedpoint_t fxp) { + return fpm_FromFloat(tan(fpm_ToFloat(fxp))); +} + fixedpoint_t fpm_ATan(fixedpoint_t fxp) { + return fpm_FromFloat(atan(fpm_ToFloat(fxp))); +} + +//These take degrees + fixedpoint_t fpm_SinDeg(fixedpoint_t fxp) { + return fpm_Sin(fpm_DivInt(fpm_Mul(fxp, FPM_PI), 180)); +} + fixedpoint_t fpm_CosDeg(fixedpoint_t fxp) { + return fpm_Cos(fpm_DivInt(fpm_Mul(fxp, FPM_PI), 180)); +} + fixedpoint_t fpm_TanDeg(fixedpoint_t fxp) { + return fpm_Tan(fpm_DivInt(fpm_Mul(fxp, FPM_PI), 180)); +} + fixedpoint_t fpm_ATanDeg(fixedpoint_t fxp) { + return fpm_ATan(fpm_DivInt(fpm_Mul(fxp, FPM_PI), 180)); +} + +/*********************************************/ +/* 8.24 routines: */ +/*********************************************/ + +fixedpoint8_24_t fpm_FromFloat8_24(double f) { +# if defined(DEBUG)&&defined(FPM_VALIDATE) + if (f) ASSERT((fixedpoint_t) (f*16777216.0)); +# endif + + return (fixedpoint8_24_t) (f*16777216.0); +} + +float fpm_ToFloat8_24(fixedpoint8_24_t fxp) { + return (float)(fxp/16777216.0); +} + +fixedpoint8_24_t fpm_FromLong8_24(long l) { +# if defined(DEBUG)&&defined(FPM_VALIDATE) + if (l>0) ASSERT((l<<24)>0); + else if (l<0) ASSERT((l<<24)<0); +# endif + + return l<<24; +} + +long fpm_ToLong8_24(fixedpoint8_24_t fxp) { + if (fxp<0) + return -((long)((fxp^0xffffffff)>>24)+1); + else + return (fxp>>24)&0x000000ff; +} + +fixedpoint8_24_t fpm_FromFixedPoint(fixedpoint_t fxp) { + return fxp<<8; +} + +fixedpoint_t fpm_ToFixedPoint(fixedpoint8_24_t fxp) { + if (fxp<0) + return -((long)((fxp^0xffffffff)>>8)+1); + else + return (fxp>>8)&0x00ffffff; +} + +fixedpoint8_24_t fpm_Add8_24(fixedpoint8_24_t fxp1, fixedpoint8_24_t fxp2) { + return fxp1+fxp2; +} + +fixedpoint8_24_t fpm_Add38_24(fixedpoint8_24_t fxp1, fixedpoint8_24_t fxp2, fixedpoint8_24_t fxp3) { + return fxp1+fxp2+fxp3; +} +/* + fixedpoint_t fpm_Inc(fixedpoint_t fxp) { + return fxp=fxp+FPM_FROMLONG(1); +} +*/ +fixedpoint8_24_t fpm_Sub8_24(fixedpoint8_24_t fxp1, fixedpoint8_24_t fxp2) { + return fxp1-fxp2; +} +/* + fixedpoint_t fpm_Dec(fixedpoint_t &fxp) { + return fxp=fxp-FPM_FROMLONG(1); +} +*/ +fixedpoint8_24_t fpm_Mul8_24(fixedpoint8_24_t fxp1, fixedpoint8_24_t fxp2) { + __int64 tmp=fxp1; + +# if defined(DEBUG)&&defined(FPM_VALIDATE) + fixedpoint8_24_t fxp; + tmp*=fxp2; + fxp=(fixedpoint8_24_t)(tmp>>24); + if (fxp1&&fxp2) { + ASSERT(fxp); + if ((fxp1>0&&fxp2>0)||(fxp1<0&&fxp2<0)) ASSERT(fxp>0); + else ASSERT(fxp<0); + } + return fxp; +# endif + + tmp*=fxp2; + return (fixedpoint_t)(tmp>>24); +} + +fixedpoint_t fpm_MulMixed8_24(fixedpoint8_24_t fxp1, fixedpoint_t fxp2) { + __int64 tmp=fxp1; + tmp*=fxp2; + + return (fixedpoint_t)(tmp>>24); +} + + fixedpoint8_24_t fpm_Div8_24(fixedpoint8_24_t fxp1, fixedpoint8_24_t fxp2) { + __int64 tmp=fxp1; +# if defined(DEBUG)&&defined(FPM_VALIDATE) + //The purpose of this is to cause an exception in Windows CE + //that will be handled right here by the debugger. Otherwise a + //divide by zero will be thrown which cannot be used to find + //where the exception actually occured with the debugger. + ASSERT(fxp2); + if (!fxp2) + (*(int *)fxp2)=0; +# endif + tmp<<=24; + return (fixedpoint8_24_t)(tmp/fxp2); +} + +fixedpoint8_24_t fpm_DivInt8_24(fixedpoint8_24_t fxp1, long l) { + return fxp1/l; +} + +fixedpoint8_24_t fpm_DivInt64_8_24(fixedpoint8_24_t fxp1, __int64 l) { + return (fixedpoint8_24_t) (fxp1/l); +} + + fixedpoint8_24_t fpm_Abs8_24(fixedpoint8_24_t fxp) { + return abs(fxp); +} + +//TODO: could be more efficient + fixedpoint8_24_t fpm_Ceil8_24(fixedpoint8_24_t fxp) { + if (fxp&0x00ffffff) { + if (fxp<=0) return (fxp&0xff000000); + return (fxp&0xff000000)+FPM_FROMLONGC8_24(1); + } + return fxp; +} +//TODO: could be more efficient + fixedpoint8_24_t fpm_Floor8_24(fixedpoint8_24_t fxp) { + if (fxp&0x00ffffff) { + if (fxp<0) return -(long)((fxp&0xff000000)+FPM_FROMLONG8_24(1)); + return fxp&0xff000000; + } + return fxp; +} + +//TODO: Implement sqrt mathematically instead of converting to float and back + fixedpoint8_24_t fpm_Sqrt8_24(fixedpoint8_24_t fxp) { + return fpm_FromFloat8_24(sqrt(fpm_ToFloat8_24(fxp))); +} + + fixedpoint8_24_t fpm_Sqr8_24(fixedpoint8_24_t fxp) { + return fpm_Mul8_24(fxp,fxp); +} + + fixedpoint8_24_t fpm_Inv8_24(fixedpoint8_24_t fxp) { +# if defined(DEBUG)&&defined(FPM_VALIDATE) + ASSERT(fxp); +# endif + + return fpm_Div8_24(FPM_FROMLONGC8_24(1), fxp); +} diff --git a/project/jni/application/quake/source/FixedPointMath.h b/project/jni/application/quake/source/FixedPointMath.h new file mode 100644 index 000000000..61f0eb35e --- /dev/null +++ b/project/jni/application/quake/source/FixedPointMath.h @@ -0,0 +1,247 @@ +#ifndef _FIXEDPOINTMATH_H +#define _FIXEDPOINTMATH_H +//Fixed point math routines (16.16) +//Dan East +//01-24-2001 + +#define FPM_PI 205887L +#define FPM_2PI 411775L +#define FPM_E 178144L +#define FPM_ROOT2 74804L +#define FPM_ROOT3 113512L +#define FPM_GOLDEN 106039L +#define FPM_MAX 0x7fff0000 + +typedef long fixedpoint_t; +typedef long fixedpoint8_24_t; + + +fixedpoint_t fpm_FromFloat(double f); +float fpm_ToFloat(fixedpoint_t fxp); + +fixedpoint_t fpm_FromLong(long l); +long fpm_ToLong(fixedpoint_t fxp); + +fixedpoint_t fpm_Add(fixedpoint_t fxp1, fixedpoint_t fxp2); +fixedpoint_t fpm_Add3(fixedpoint_t fxp1, fixedpoint_t fxp2, fixedpoint_t fxp3); + +fixedpoint_t fpm_Sub(fixedpoint_t fxp1, fixedpoint_t fxp2); + +fixedpoint_t fpm_Mul(fixedpoint_t fxp1, fixedpoint_t fxp2); + +fixedpoint_t fpm_Div(fixedpoint_t fxp1, fixedpoint_t fxp2); +fixedpoint_t fpm_DivInt(fixedpoint_t fxp1, long l); +fixedpoint_t fpm_Abs(fixedpoint_t fxp); + +fixedpoint_t fpm_Ceil(fixedpoint_t fxp); +fixedpoint_t fpm_Floor(fixedpoint_t fxp); + +fixedpoint_t fpm_Sqrt(fixedpoint_t fxp); +fixedpoint_t fpm_Sqr(fixedpoint_t fxp); + +fixedpoint_t fpm_Inv(fixedpoint_t fxp); + +fixedpoint_t fpm_Sin(fixedpoint_t fxp); +fixedpoint_t fpm_Cos(fixedpoint_t fxp); +fixedpoint_t fpm_Tan(fixedpoint_t fxp); +fixedpoint_t fpm_ATan(fixedpoint_t fxp); +//These take degrees +fixedpoint_t fpm_SinDeg(fixedpoint_t fxp); +fixedpoint_t fpm_CosDeg(fixedpoint_t fxp); +fixedpoint_t fpm_TanDeg(fixedpoint_t fxp); +fixedpoint_t fpm_ATanDeg(fixedpoint_t fxp); + + +#define FPM_FROMFLOAT(f) fpm_FromFloat(f) +#define FPM_FROMFLOATC(f) ((long)((f) * 65536.0 )) //Constant version +#define FPM_TOFLOAT(fxp) fpm_ToFloat(fxp) + +#define FPM_FROMLONG(l) fpm_FromLong(l) +#define FPM_FROMLONGC(l) ((l)<<16) //Constant version +#define FPM_TOLONG(l) fpm_ToLong(l) + +#define FPM_ADD(f1, f2) fpm_Add(f1, f2) +#define FPM_ADD3(f1, f2, f3) fpm_Add3(f1, f2, f3) +#define FPM_INC(f1) ((f1)=FPM_ADD(f1, FPM_FROMLONG(1))) + +#define FPM_SUB(f1, f2) fpm_Sub(f1, f2) +#define FPM_DEC(f1) ((f1)=FPM_SUB(f1, FPM_FROMLONG(1))) + +#define FPM_MUL(f1, f2) fpm_Mul(f1, f2) + +#define FPM_DIV(n, d) fpm_Div(n, d) +#define FPM_DIVINT(n, d) fpm_DivInt(n, d) + +#define FPM_ABS(fxp) fpm_Abs(fxp) + +#define FPM_CEIL(fxp) fpm_Ceil(fxp) +#define FPM_FLOOR(fxp) fpm_Floor(fxp) + +#define FPM_SQRT(fxp) fpm_Sqrt(fxp) +#define FPM_SQR(fxp) fpm_Sqr(fxp) + +#define FPM_INV(fxp) fpm_Inv(fxp) + +//These take radians +#define FPM_SIN(r) fpm_Sin(r) +#define FPM_COS(r) fpm_Cos(r) +#define FPM_TAN(r) fpm_Tan(r) +#define FPM_ATAN(r) fpm_ATan(r) + +//These take degrees +#define FPM_SIN_DEG(d) fpm_SinDeg(d) +#define FPM_COS_DEG(d) fpm_CosDeg(d) +#define FPM_TAN_DEG(d) fpm_TanDeg(d) +#define FPM_ATAN_DEG(d) fpm_ATanDeg(d) + +fixedpoint8_24_t fpm_FromFloat(double f); +float fpm_ToFloat8_24(fixedpoint8_24_t fxp); + +fixedpoint8_24_t fpm_FromLong8_24(long l); +long fpm_ToLong8_24(fixedpoint8_24_t fxp); + +fixedpoint8_24_t fpm_FromFixedPoint(fixedpoint_t fxp); +fixedpoint_t fpm_ToFixedPoint(fixedpoint8_24_t fxp); + +fixedpoint8_24_t fpm_Add8_24(fixedpoint8_24_t fxp1, fixedpoint8_24_t fxp2); +fixedpoint8_24_t fpm_Add38_24(fixedpoint8_24_t fxp1, fixedpoint8_24_t fxp2, fixedpoint8_24_t fxp3); + +fixedpoint8_24_t fpm_Sub8_24(fixedpoint8_24_t fxp1, fixedpoint8_24_t fxp2); + +fixedpoint8_24_t fpm_Mul8_24(fixedpoint8_24_t fxp1, fixedpoint8_24_t fxp2); +fixedpoint_t fpm_MulMixed8_24(fixedpoint8_24_t fxp1, fixedpoint_t fxp2); + +fixedpoint8_24_t fpm_Div8_24(fixedpoint8_24_t fxp1, fixedpoint8_24_t fxp2); +fixedpoint8_24_t fpm_DivInt8_24(fixedpoint8_24_t fxp1, long l); +fixedpoint8_24_t fpm_DivInt64_8_24(fixedpoint8_24_t fxp1, __int64 l); + +fixedpoint8_24_t fpm_Abs8_24(fixedpoint8_24_t fxp); + +fixedpoint8_24_t fpm_Ceil8_24(fixedpoint8_24_t fxp); +fixedpoint8_24_t fpm_Floor8_24(fixedpoint8_24_t fxp); + +fixedpoint8_24_t fpm_Sqrt8_24(fixedpoint8_24_t fxp); +fixedpoint8_24_t fpm_Sqr8_24(fixedpoint8_24_t fxp); + +fixedpoint8_24_t fpm_Inv8_24(fixedpoint8_24_t fxp); + + +#define FPM_FROMFLOAT8_24(f) fpm_FromFloat8_24(f) +#define FPM_FROMFLOATC8_24(f) ((long)((f) * 16777216.0 )) //Constant version +#define FPM_TOFLOAT8_24(fxp) fpm_ToFloat8_24(fxp) + +#define FPM_FROMLONG8_24(l) fpm_FromLong8_24(l) +#define FPM_FROMLONGC8_24(l) ((l)<<24) //Constant version +#define FPM_TOLONG8_24(l) fpm_ToLong8_24(l) + + +/* +extern __int64 FPM_TMPVAR_INT64; + + #define FPM_FROMFLOAT(f) ((long)((f) * 65536.0 )) //+0.5 +#define FPM_TOFLOAT(fxp) (((float)(fxp)) / 65536.0) + +#define FPM_FROMLONG(l) ((l)<<16) +#define FPM_TOLONG(l) ((l)<0?(-(long)((l)^0xffffffff)>>16):(((l)>>16)&0x0000ffff)) + +#define FPM_ADD(f1, f2) ((f1)+(f2)) +#define FPM_ADD3(f1, f2, f3) ((f1)+(f2)+(f3)) +#define FPM_INC(f1) ((f1)=FPM_ADD(f1, FPM_FROMLONG(1))) + +#define FPM_SUB(f1, f2) ((f1)-(f2)) +#define FPM_DEC(f1) ((f1)=FPM_SUB(f1, FPM_FROMLONG(1))) + +#define FPM_MUL(f1, f2) (((f1)>>8)*((f2)>>8)) +//#define FPM_MUL(f1, f2) ((fixedpoint_t)((FPM_TMPVAR_INT64=(f1))*(f2))>>16) +//#define FPM_MUL(f1, f2) (((f1)*(f2))>>16) +//TODO: This needs to be done without copying to another var +#define FPM_DIV(n, d) ((fixedpoint_t)(((FPM_TMPVAR_INT64=(n))<<16)/d)) +#define FPM_DIVINT(n, d) ((fixedpoint_t)((n)/(d))) +//#define FPM_DIV(n, d) ((long)(((__int64)n)<<16)/(d)) + +#define FPM_ABS(fxp) (abs(fxp)) + +//TODO: could be more effecient +#define FPM_CEIL(fxp) ((fxp)&0x0000ffff?((fxp)<=0?((fxp)&0xffff0000):(((fxp)&0xffff0000)+FPM_FROMLONG(1))):(fxp)) +#define FPM_FLOOR(fxp) ((fxp)&0x0000ffff?((fxp)<0?(((fxp)&0xffff0000)-FPM_FROMLONG(1)):((fxp)&0xffff0000)):(fxp)) + +//TODO: Implement sqrt mathematically instead of converting to float and back +#define FPM_SQRT(fxp) (FPM_FROMFLOAT(sqrt(FPM_TOFLOAT(fxp)))) +#define FPM_SQR(fxp) (FPM_MUL(fxp,fxp)>>16) + +#define FPM_INV(fxp) (FPM_DIV(0x10000, fxp)) +//TODO: Calc trig functions (or lookup) instead of converting to float and back +//These take radians +#define FPM_SIN(r) (FPM_FROMFLOAT(sin(FPM_TOFLOAT(r)))) +#define FPM_COS(r) (FPM_FROMFLOAT(cos(FPM_TOFLOAT(r)))) +#define FPM_TAN(r) (FPM_FROMFLOAT(tan(FPM_TOFLOAT(r)))) +#define FPM_ATAN(r) (FPM_FROMFLOAT(atan(FPM_TOFLOAT(r)))) + +//These take degrees +#define FPM_SIN_DEG(d) (FPM_SIN(FPM_DIV(FPM_MUL(d,FPM_PI),0xB40000))) //0xB40000 = 180.0 +#define FPM_COS_DEG(d) (FPM_COS(FPM_DIV(FPM_MUL(d,FPM_PI),0xB40000))) +#define FPM_TAN_DEG(d) (FPM_TAN(FPM_DIV(FPM_MUL(d,FPM_PI),0xB40000))) +#define FPM_ATAN_DEG(d) (FPM_ATAN(FPM_DIV(FPM_MUL(d,FPM_PI),0xB40000))) + +*/ +/* +#define FPM_PI 3.14 +#define FPM_2PI (3.14*2) +#define FPM_E 178144L +#define FPM_ROOT2 74804L +#define FPM_ROOT3 113512L +#define FPM_GOLDEN 106039L + + +typedef float fixedpoint_t; +//This variable must be declared in one of the implementation files. +extern __int64 FPM_TMPVAR_INT64; + +#define FPM_FROMFLOAT(f) (f) +#define FPM_TOFLOAT(fxp) (fxp) + +#define FPM_FROMLONG(l) ((float)l) +#define FPM_TOLONG(fxp) ((long)fxp) + +#define FPM_ADD(f1, f2) ((f1)+(f2)) +#define FPM_ADD3(f1, f2, f3) ((f1)+(f2)+(f3)) +#define FPM_INC(f1) ((f1)++) + +#define FPM_SUB(f1, f2) ((f1)-(f2)) +#define FPM_DEC(f1) ((f1)--) + +#define FPM_MUL(f1, f2) ((f1)*(f2)) +//#define FPM_MUL(f1, f2) ((fixedpoint_t)((FPM_TMPVAR_INT64=(f1))*(f2))>>16) +//#define FPM_MUL(f1, f2) (((f1)*(f2))>>16) +//TODO: This needs to be done without copying to another var +#define FPM_DIV(n, d) ((n)/(d)) +//#define FPM_DIV(n, d) ((long)(((__int64)n)<<16)/(d)) + +#define FPM_ABS(fxp) (abs(fxp)) + +//TODO: Implement ceil mathematically instead of converting to float and back +#define FPM_CEIL(fxp) (ceil(fxp)) +#define FPM_FLOOR(fxp) (floor(fxp)) + +//TODO: Implement sqrt mathematically instead of converting to float and back +#define FPM_SQRT(fxp) (sqrt(fxp)) +#define FPM_SQR(fxp) ((fxp)*(fxp)) + +#define FPM_INV(fxp) (1/(fxp)) +//TODO: Calc trig functions (or lookup) instead of converting to float and back +//These take radians +#define FPM_SIN(r) (sin(r)) +#define FPM_COS(r) (cos(r)) +#define FPM_TAN(r) (tan(r)) +#define FPM_ATAN(r) (atan(r)) + +//These take degrees +#define FPM_SIN_DEG(d) FPM_SIN(((d)*FPM_PI)/180.0) //0xB40000 = 180.0 +#define FPM_COS_DEG(d) FPM_COS(((d)*FPM_PI)/180.0) +#define FPM_TAN_DEG(d) FPM_TAN(((d)*FPM_PI)/180.0) +#define FPM_ATAN_DEG(d) FPM_ATAN(((d)*FPM_PI)/180.0) +*/ + +#endif //_FIXEDPOINTMATH_H + + diff --git a/project/jni/application/quake/source/LogFloat.c b/project/jni/application/quake/source/LogFloat.c new file mode 100644 index 000000000..709abe87a --- /dev/null +++ b/project/jni/application/quake/source/LogFloat.c @@ -0,0 +1,113 @@ +//LogFloat.c +//Logs max, min and precision of a floating point value +#include +#include "LogFloat.h" + +struct LogFloatEntry { + char id[128]; + float min, max, precision; + int counter; +}; + +#define MAX_LF_ENTRIES 1000 +struct LogFloatEntry lf_entries[MAX_LF_ENTRIES]; +int lf_total=0; + +_inline struct LogFloatEntry *_lfAdd(char *id) { + //Adds a new entry. + //NULL == Array full. + + if (lf_total==MAX_LF_ENTRIES) return NULL; + + strcpy(lf_entries[lf_total].id, id); + lf_entries[lf_total].max=lf_entries[lf_total].min=0.0f; + lf_entries[lf_total].precision=1.0f; + lf_entries[lf_total].counter=0; + + return &lf_entries[lf_total++]; +} + +_inline struct LogFloatEntry *_lfFind(char *id) { + //Finds an existing entry. + //NULL == No matching id + + struct LogFloatEntry *cur=&lf_entries[0], *last=&lf_entries[lf_total]; + while (cur<=last) { + //Change this is case insensitive matching is desired. + if (!strcmp(id, cur->id)) return cur; + cur++; + } + + return NULL; +} + +_inline struct LogFloatEntry *_lfGet(char *id) { + //Gets an entry. Returns an entry if it already exists, otherwise a new entry is created. + struct LogFloatEntry *cur=_lfFind(id); + + if (!cur) cur=_lfAdd(id); + return cur; +} + +int LogFloatInit() { + + lf_total=0; + return 1; +} + +void LogFloatClose() { + lf_total=0; +} + +void LogFloatResults(char *fn) { + int i; + FILE *f=fopen(fn, "w+"); + + if (f) { + fprintf(f, "ID\tMin\tMax\tPrecision\tCount\n\n"); + for (i=0; i=0 && <= 32, return value is f truncated to the fixed point precision "precision". + //otherwise return value == f. + + struct LogFloatEntry *cur; + float tmp; + + if (index>=0) { + char newId[256]; + sprintf(newId, "%s[%d]", id, index); + cur=_lfGet(newId); + } else cur=_lfGet(id); + + if (cur) { + cur->counter++; + if (cur->maxmax=f; + if (cur->min>f) cur->min=f; + tmp=(float)fabs(f); + if (tmp<1.0f&&f!=0.0f) + if (tmpprecision) cur->precision=tmp; + } //else Error: we ran out of entry storage + + if (precision>=0) { + float f2=(float)(2^precision); + tmp=f*f2; + return tmp/f2; + } + + return f; +} \ No newline at end of file diff --git a/project/jni/application/quake/source/LogFloat.h b/project/jni/application/quake/source/LogFloat.h new file mode 100644 index 000000000..9ebb693e2 --- /dev/null +++ b/project/jni/application/quake/source/LogFloat.h @@ -0,0 +1,10 @@ +#ifndef LOGFLOAT_H +#define LOGFLOAT_H + +int LogFloatInit(); +void LogFloatClose(); + +void LogFloatResults(char *fn); + +float LogFloat(float f, char *id, int index, int precision); +#endif diff --git a/project/jni/application/quake/source/adivtab.h b/project/jni/application/quake/source/adivtab.h new file mode 100644 index 000000000..571690665 --- /dev/null +++ b/project/jni/application/quake/source/adivtab.h @@ -0,0 +1,1077 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// table of quotients and remainders for [-15...16] / [-15...16] + +// numerator = -15 +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{1, -5}, +{1, -6}, +{1, -7}, +{2, -1}, +{2, -3}, +{3, 0}, +{3, -3}, +{5, 0}, +{7, -1}, +{15, 0}, +{0, 0}, +{-15, 0}, +{-8, 1}, +{-5, 0}, +{-4, 1}, +{-3, 0}, +{-3, 3}, +{-3, 6}, +{-2, 1}, +{-2, 3}, +{-2, 5}, +{-2, 7}, +{-2, 9}, +{-2, 11}, +{-2, 13}, +{-1, 0}, +{-1, 1}, +// numerator = -14 +{0, -14}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{1, -5}, +{1, -6}, +{2, 0}, +{2, -2}, +{2, -4}, +{3, -2}, +{4, -2}, +{7, 0}, +{14, 0}, +{0, 0}, +{-14, 0}, +{-7, 0}, +{-5, 1}, +{-4, 2}, +{-3, 1}, +{-3, 4}, +{-2, 0}, +{-2, 2}, +{-2, 4}, +{-2, 6}, +{-2, 8}, +{-2, 10}, +{-2, 12}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +// numerator = -13 +{0, -13}, +{0, -13}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{1, -5}, +{1, -6}, +{2, -1}, +{2, -3}, +{3, -1}, +{4, -1}, +{6, -1}, +{13, 0}, +{0, 0}, +{-13, 0}, +{-7, 1}, +{-5, 2}, +{-4, 3}, +{-3, 2}, +{-3, 5}, +{-2, 1}, +{-2, 3}, +{-2, 5}, +{-2, 7}, +{-2, 9}, +{-2, 11}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +// numerator = -12 +{0, -12}, +{0, -12}, +{0, -12}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{1, -5}, +{2, 0}, +{2, -2}, +{3, 0}, +{4, 0}, +{6, 0}, +{12, 0}, +{0, 0}, +{-12, 0}, +{-6, 0}, +{-4, 0}, +{-3, 0}, +{-3, 3}, +{-2, 0}, +{-2, 2}, +{-2, 4}, +{-2, 6}, +{-2, 8}, +{-2, 10}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +// numerator = -11 +{0, -11}, +{0, -11}, +{0, -11}, +{0, -11}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{1, -5}, +{2, -1}, +{2, -3}, +{3, -2}, +{5, -1}, +{11, 0}, +{0, 0}, +{-11, 0}, +{-6, 1}, +{-4, 1}, +{-3, 1}, +{-3, 4}, +{-2, 1}, +{-2, 3}, +{-2, 5}, +{-2, 7}, +{-2, 9}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +// numerator = -10 +{0, -10}, +{0, -10}, +{0, -10}, +{0, -10}, +{0, -10}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{2, 0}, +{2, -2}, +{3, -1}, +{5, 0}, +{10, 0}, +{0, 0}, +{-10, 0}, +{-5, 0}, +{-4, 2}, +{-3, 2}, +{-2, 0}, +{-2, 2}, +{-2, 4}, +{-2, 6}, +{-2, 8}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +// numerator = -9 +{0, -9}, +{0, -9}, +{0, -9}, +{0, -9}, +{0, -9}, +{0, -9}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{1, -4}, +{2, -1}, +{3, 0}, +{4, -1}, +{9, 0}, +{0, 0}, +{-9, 0}, +{-5, 1}, +{-3, 0}, +{-3, 3}, +{-2, 1}, +{-2, 3}, +{-2, 5}, +{-2, 7}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +// numerator = -8 +{0, -8}, +{0, -8}, +{0, -8}, +{0, -8}, +{0, -8}, +{0, -8}, +{0, -8}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{2, 0}, +{2, -2}, +{4, 0}, +{8, 0}, +{0, 0}, +{-8, 0}, +{-4, 0}, +{-3, 1}, +{-2, 0}, +{-2, 2}, +{-2, 4}, +{-2, 6}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +// numerator = -7 +{0, -7}, +{0, -7}, +{0, -7}, +{0, -7}, +{0, -7}, +{0, -7}, +{0, -7}, +{0, -7}, +{1, 0}, +{1, -1}, +{1, -2}, +{1, -3}, +{2, -1}, +{3, -1}, +{7, 0}, +{0, 0}, +{-7, 0}, +{-4, 1}, +{-3, 2}, +{-2, 1}, +{-2, 3}, +{-2, 5}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +// numerator = -6 +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{0, -6}, +{1, 0}, +{1, -1}, +{1, -2}, +{2, 0}, +{3, 0}, +{6, 0}, +{0, 0}, +{-6, 0}, +{-3, 0}, +{-2, 0}, +{-2, 2}, +{-2, 4}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +// numerator = -5 +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{0, -5}, +{1, 0}, +{1, -1}, +{1, -2}, +{2, -1}, +{5, 0}, +{0, 0}, +{-5, 0}, +{-3, 1}, +{-2, 1}, +{-2, 3}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +{-1, 11}, +// numerator = -4 +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{0, -4}, +{1, 0}, +{1, -1}, +{2, 0}, +{4, 0}, +{0, 0}, +{-4, 0}, +{-2, 0}, +{-2, 2}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +{-1, 11}, +{-1, 12}, +// numerator = -3 +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{0, -3}, +{1, 0}, +{1, -1}, +{3, 0}, +{0, 0}, +{-3, 0}, +{-2, 1}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +{-1, 11}, +{-1, 12}, +{-1, 13}, +// numerator = -2 +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{0, -2}, +{1, 0}, +{2, 0}, +{0, 0}, +{-2, 0}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +{-1, 11}, +{-1, 12}, +{-1, 13}, +{-1, 14}, +// numerator = -1 +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{0, -1}, +{1, 0}, +{0, 0}, +{-1, 0}, +{-1, 1}, +{-1, 2}, +{-1, 3}, +{-1, 4}, +{-1, 5}, +{-1, 6}, +{-1, 7}, +{-1, 8}, +{-1, 9}, +{-1, 10}, +{-1, 11}, +{-1, 12}, +{-1, 13}, +{-1, 14}, +{-1, 15}, +// numerator = 0 +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +{0, 0}, +// numerator = 1 +{-1, -14}, +{-1, -13}, +{-1, -12}, +{-1, -11}, +{-1, -10}, +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{0, 0}, +{1, 0}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +{0, 1}, +// numerator = 2 +{-1, -13}, +{-1, -12}, +{-1, -11}, +{-1, -10}, +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, 0}, +{0, 0}, +{2, 0}, +{1, 0}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +{0, 2}, +// numerator = 3 +{-1, -12}, +{-1, -11}, +{-1, -10}, +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -1}, +{-3, 0}, +{0, 0}, +{3, 0}, +{1, 1}, +{1, 0}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +{0, 3}, +// numerator = 4 +{-1, -11}, +{-1, -10}, +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -2}, +{-2, 0}, +{-4, 0}, +{0, 0}, +{4, 0}, +{2, 0}, +{1, 1}, +{1, 0}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +{0, 4}, +// numerator = 5 +{-1, -10}, +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -3}, +{-2, -1}, +{-3, -1}, +{-5, 0}, +{0, 0}, +{5, 0}, +{2, 1}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +{0, 5}, +// numerator = 6 +{-1, -9}, +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, 0}, +{-6, 0}, +{0, 0}, +{6, 0}, +{3, 0}, +{2, 0}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +{0, 6}, +// numerator = 7 +{-1, -8}, +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -5}, +{-2, -3}, +{-2, -1}, +{-3, -2}, +{-4, -1}, +{-7, 0}, +{0, 0}, +{7, 0}, +{3, 1}, +{2, 1}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +{0, 7}, +// numerator = 8 +{-1, -7}, +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -6}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, -1}, +{-4, 0}, +{-8, 0}, +{0, 0}, +{8, 0}, +{4, 0}, +{2, 2}, +{2, 0}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 8}, +{0, 8}, +{0, 8}, +{0, 8}, +{0, 8}, +{0, 8}, +{0, 8}, +{0, 8}, +// numerator = 9 +{-1, -6}, +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -7}, +{-2, -5}, +{-2, -3}, +{-2, -1}, +{-3, -3}, +{-3, 0}, +{-5, -1}, +{-9, 0}, +{0, 0}, +{9, 0}, +{4, 1}, +{3, 0}, +{2, 1}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 9}, +{0, 9}, +{0, 9}, +{0, 9}, +{0, 9}, +{0, 9}, +{0, 9}, +// numerator = 10 +{-1, -5}, +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -8}, +{-2, -6}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, -2}, +{-4, -2}, +{-5, 0}, +{-10, 0}, +{0, 0}, +{10, 0}, +{5, 0}, +{3, 1}, +{2, 2}, +{2, 0}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 10}, +{0, 10}, +{0, 10}, +{0, 10}, +{0, 10}, +{0, 10}, +// numerator = 11 +{-1, -4}, +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -9}, +{-2, -7}, +{-2, -5}, +{-2, -3}, +{-2, -1}, +{-3, -4}, +{-3, -1}, +{-4, -1}, +{-6, -1}, +{-11, 0}, +{0, 0}, +{11, 0}, +{5, 1}, +{3, 2}, +{2, 3}, +{2, 1}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 11}, +{0, 11}, +{0, 11}, +{0, 11}, +{0, 11}, +// numerator = 12 +{-1, -3}, +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -10}, +{-2, -8}, +{-2, -6}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, -3}, +{-3, 0}, +{-4, 0}, +{-6, 0}, +{-12, 0}, +{0, 0}, +{12, 0}, +{6, 0}, +{4, 0}, +{3, 0}, +{2, 2}, +{2, 0}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 12}, +{0, 12}, +{0, 12}, +{0, 12}, +// numerator = 13 +{-1, -2}, +{-1, -1}, +{-1, 0}, +{-2, -11}, +{-2, -9}, +{-2, -7}, +{-2, -5}, +{-2, -3}, +{-2, -1}, +{-3, -5}, +{-3, -2}, +{-4, -3}, +{-5, -2}, +{-7, -1}, +{-13, 0}, +{0, 0}, +{13, 0}, +{6, 1}, +{4, 1}, +{3, 1}, +{2, 3}, +{2, 1}, +{1, 6}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 13}, +{0, 13}, +{0, 13}, +// numerator = 14 +{-1, -1}, +{-1, 0}, +{-2, -12}, +{-2, -10}, +{-2, -8}, +{-2, -6}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, -4}, +{-3, -1}, +{-4, -2}, +{-5, -1}, +{-7, 0}, +{-14, 0}, +{0, 0}, +{14, 0}, +{7, 0}, +{4, 2}, +{3, 2}, +{2, 4}, +{2, 2}, +{2, 0}, +{1, 6}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 14}, +{0, 14}, +// numerator = 15 +{-1, 0}, +{-2, -13}, +{-2, -11}, +{-2, -9}, +{-2, -7}, +{-2, -5}, +{-2, -3}, +{-2, -1}, +{-3, -6}, +{-3, -3}, +{-3, 0}, +{-4, -1}, +{-5, 0}, +{-8, -1}, +{-15, 0}, +{0, 0}, +{15, 0}, +{7, 1}, +{5, 0}, +{3, 3}, +{3, 0}, +{2, 3}, +{2, 1}, +{1, 7}, +{1, 6}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, +{0, 15}, +// numerator = 16 +{-2, -14}, +{-2, -12}, +{-2, -10}, +{-2, -8}, +{-2, -6}, +{-2, -4}, +{-2, -2}, +{-2, 0}, +{-3, -5}, +{-3, -2}, +{-4, -4}, +{-4, 0}, +{-6, -2}, +{-8, 0}, +{-16, 0}, +{0, 0}, +{16, 0}, +{8, 0}, +{5, 1}, +{4, 0}, +{3, 1}, +{2, 4}, +{2, 2}, +{2, 0}, +{1, 7}, +{1, 6}, +{1, 5}, +{1, 4}, +{1, 3}, +{1, 2}, +{1, 1}, +{1, 0}, diff --git a/project/jni/application/quake/source/anorms.h b/project/jni/application/quake/source/anorms.h new file mode 100644 index 000000000..aecd4f2d2 --- /dev/null +++ b/project/jni/application/quake/source/anorms.h @@ -0,0 +1,183 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +//Dan: I added all the float casts because I was tired of seeing 508 warnings +//every time I compiled. +{(float)-0.525731, (float)0.000000, (float)0.850651}, +{(float)-0.442863, (float)0.238856, (float)0.864188}, +{(float)-0.295242, (float)0.000000, (float)0.955423}, +{(float)-0.309017, (float)0.500000, (float)0.809017}, +{(float)-0.162460, (float)0.262866, (float)0.951056}, +{(float)0.000000, (float)0.000000, (float)1.000000}, +{(float)0.000000, (float)0.850651, (float)0.525731}, +{(float)-0.147621, (float)0.716567, (float)0.681718}, +{(float)0.147621, (float)0.716567, (float)0.681718}, +{(float)0.000000, (float)0.525731, (float)0.850651}, +{(float)0.309017, (float)0.500000, (float)0.809017}, +{(float)0.525731, (float)0.000000, (float)0.850651}, +{(float)0.295242, (float)0.000000, (float)0.955423}, +{(float)0.442863, (float)0.238856, (float)0.864188}, +{(float)0.162460, (float)0.262866, (float)0.951056}, +{(float)-0.681718, (float)0.147621, (float)0.716567}, +{(float)-0.809017, (float)0.309017, (float)0.500000}, +{(float)-0.587785, (float)0.425325, (float)0.688191}, +{(float)-0.850651, (float)0.525731, (float)0.000000}, +{(float)-0.864188, (float)0.442863, (float)0.238856}, +{(float)-0.716567, (float)0.681718, (float)0.147621}, +{(float)-0.688191, (float)0.587785, (float)0.425325}, +{(float)-0.500000, (float)0.809017, (float)0.309017}, +{(float)-0.238856, (float)0.864188, (float)0.442863}, +{(float)-0.425325, (float)0.688191, (float)0.587785}, +{(float)-0.716567, (float)0.681718, (float)-0.147621}, +{(float)-0.500000, (float)0.809017, (float)-0.309017}, +{(float)-0.525731, (float)0.850651, (float)0.000000}, +{(float)0.000000, (float)0.850651, (float)-0.525731}, +{(float)-0.238856, (float)0.864188, (float)-0.442863}, +{(float)0.000000, (float)0.955423, (float)-0.295242}, +{(float)-0.262866, (float)0.951056, (float)-0.162460}, +{(float)0.000000, (float)1.000000, (float)0.000000}, +{(float)0.000000, (float)0.955423, (float)0.295242}, +{(float)-0.262866, (float)0.951056, (float)0.162460}, +{(float)0.238856, (float)0.864188, (float)0.442863}, +{(float)0.262866, (float)0.951056, (float)0.162460}, +{(float)0.500000, (float)0.809017, (float)0.309017}, +{(float)0.238856, (float)0.864188, (float)-0.442863}, +{(float)0.262866, (float)0.951056, (float)-0.162460}, +{(float)0.500000, (float)0.809017, (float)-0.309017}, +{(float)0.850651, (float)0.525731, (float)0.000000}, +{(float)0.716567, (float)0.681718, (float)0.147621}, +{(float)0.716567, (float)0.681718, (float)-0.147621}, +{(float)0.525731, (float)0.850651, (float)0.000000}, +{(float)0.425325, (float)0.688191, (float)0.587785}, +{(float)0.864188, (float)0.442863, (float)0.238856}, +{(float)0.688191, (float)0.587785, (float)0.425325}, +{(float)0.809017, (float)0.309017, (float)0.500000}, +{(float)0.681718, (float)0.147621, (float)0.716567}, +{(float)0.587785, (float)0.425325, (float)0.688191}, +{(float)0.955423, (float)0.295242, (float)0.000000}, +{(float)1.000000, (float)0.000000, (float)0.000000}, +{(float)0.951056, (float)0.162460, (float)0.262866}, +{(float)0.850651, (float)-0.525731, (float)0.000000}, +{(float)0.955423, (float)-0.295242, (float)0.000000}, +{(float)0.864188, (float)-0.442863, (float)0.238856}, +{(float)0.951056, (float)-0.162460, (float)0.262866}, +{(float)0.809017, (float)-0.309017, (float)0.500000}, +{(float)0.681718, (float)-0.147621, (float)0.716567}, +{(float)0.850651, (float)0.000000, (float)0.525731}, +{(float)0.864188, (float)0.442863, (float)-0.238856}, +{(float)0.809017, (float)0.309017, (float)-0.500000}, +{(float)0.951056, (float)0.162460, (float)-0.262866}, +{(float)0.525731, (float)0.000000, (float)-0.850651}, +{(float)0.681718, (float)0.147621, (float)-0.716567}, +{(float)0.681718, (float)-0.147621, (float)-0.716567}, +{(float)0.850651, (float)0.000000, (float)-0.525731}, +{(float)0.809017, (float)-0.309017, (float)-0.500000}, +{(float)0.864188, (float)-0.442863, (float)-0.238856}, +{(float)0.951056, (float)-0.162460, (float)-0.262866}, +{(float)0.147621, (float)0.716567, (float)-0.681718}, +{(float)0.309017, (float)0.500000, (float)-0.809017}, +{(float)0.425325, (float)0.688191, (float)-0.587785}, +{(float)0.442863, (float)0.238856, (float)-0.864188}, +{(float)0.587785, (float)0.425325, (float)-0.688191}, +{(float)0.688191, (float)0.587785, (float)-0.425325}, +{(float)-0.147621, (float)0.716567, (float)-0.681718}, +{(float)-0.309017, (float)0.500000, (float)-0.809017}, +{(float)0.000000, (float)0.525731, (float)-0.850651}, +{(float)-0.525731, (float)0.000000, (float)-0.850651}, +{(float)-0.442863, (float)0.238856, (float)-0.864188}, +{(float)-0.295242, (float)0.000000, (float)-0.955423}, +{(float)-0.162460, (float)0.262866, (float)-0.951056}, +{(float)0.000000, (float)0.000000, (float)-1.000000}, +{(float)0.295242, (float)0.000000, (float)-0.955423}, +{(float)0.162460, (float)0.262866, (float)-0.951056}, +{(float)-0.442863, (float)-0.238856, (float)-0.864188}, +{(float)-0.309017, (float)-0.500000, (float)-0.809017}, +{(float)-0.162460, (float)-0.262866, (float)-0.951056}, +{(float)0.000000, (float)-0.850651, (float)-0.525731}, +{(float)-0.147621, (float)-0.716567, (float)-0.681718}, +{(float)0.147621, (float)-0.716567, (float)-0.681718}, +{(float)0.000000, (float)-0.525731, (float)-0.850651}, +{(float)0.309017, (float)-0.500000, (float)-0.809017}, +{(float)0.442863, (float)-0.238856, (float)-0.864188}, +{(float)0.162460, (float)-0.262866, (float)-0.951056}, +{(float)0.238856, (float)-0.864188, (float)-0.442863}, +{(float)0.500000, (float)-0.809017, (float)-0.309017}, +{(float)0.425325, (float)-0.688191, (float)-0.587785}, +{(float)0.716567, (float)-0.681718, (float)-0.147621}, +{(float)0.688191, (float)-0.587785, (float)-0.425325}, +{(float)0.587785, (float)-0.425325, (float)-0.688191}, +{(float)0.000000, (float)-0.955423, (float)-0.295242}, +{(float)0.000000, (float)-1.000000, (float)0.000000}, +{(float)0.262866, (float)-0.951056, (float)-0.162460}, +{(float)0.000000, (float)-0.850651, (float)0.525731}, +{(float)0.000000, (float)-0.955423, (float)0.295242}, +{(float)0.238856, (float)-0.864188, (float)0.442863}, +{(float)0.262866, (float)-0.951056, (float)0.162460}, +{(float)0.500000, (float)-0.809017, (float)0.309017}, +{(float)0.716567, (float)-0.681718, (float)0.147621}, +{(float)0.525731, (float)-0.850651, (float)0.000000}, +{(float)-0.238856, (float)-0.864188, (float)-0.442863}, +{(float)-0.500000, (float)-0.809017, (float)-0.309017}, +{(float)-0.262866, (float)-0.951056, (float)-0.162460}, +{(float)-0.850651, (float)-0.525731, (float)0.000000}, +{(float)-0.716567, (float)-0.681718, (float)-0.147621}, +{(float)-0.716567, (float)-0.681718, (float)0.147621}, +{(float)-0.525731, (float)-0.850651, (float)0.000000}, +{(float)-0.500000, (float)-0.809017, (float)0.309017}, +{(float)-0.238856, (float)-0.864188, (float)0.442863}, +{(float)-0.262866, (float)-0.951056, (float)0.162460}, +{(float)-0.864188, (float)-0.442863, (float)0.238856}, +{(float)-0.809017, (float)-0.309017, (float)0.500000}, +{(float)-0.688191, (float)-0.587785, (float)0.425325}, +{(float)-0.681718, (float)-0.147621, (float)0.716567}, +{(float)-0.442863, (float)-0.238856, (float)0.864188}, +{(float)-0.587785, (float)-0.425325, (float)0.688191}, +{(float)-0.309017, (float)-0.500000, (float)0.809017}, +{(float)-0.147621, (float)-0.716567, (float)0.681718}, +{(float)-0.425325, (float)-0.688191, (float)0.587785}, +{(float)-0.162460, (float)-0.262866, (float)0.951056}, +{(float)0.442863, (float)-0.238856, (float)0.864188}, +{(float)0.162460, (float)-0.262866, (float)0.951056}, +{(float)0.309017, (float)-0.500000, (float)0.809017}, +{(float)0.147621, (float)-0.716567, (float)0.681718}, +{(float)0.000000, (float)-0.525731, (float)0.850651}, +{(float)0.425325, (float)-0.688191, (float)0.587785}, +{(float)0.587785, (float)-0.425325, (float)0.688191}, +{(float)0.688191, (float)-0.587785, (float)0.425325}, +{(float)-0.955423, (float)0.295242, (float)0.000000}, +{(float)-0.951056, (float)0.162460, (float)0.262866}, +{(float)-1.000000, (float)0.000000, (float)0.000000}, +{(float)-0.850651, (float)0.000000, (float)0.525731}, +{(float)-0.955423, (float)-0.295242, (float)0.000000}, +{(float)-0.951056, (float)-0.162460, (float)0.262866}, +{(float)-0.864188, (float)0.442863, (float)-0.238856}, +{(float)-0.951056, (float)0.162460, (float)-0.262866}, +{(float)-0.809017, (float)0.309017, (float)-0.500000}, +{(float)-0.864188, (float)-0.442863, (float)-0.238856}, +{(float)-0.951056, (float)-0.162460, (float)-0.262866}, +{(float)-0.809017, (float)-0.309017, (float)-0.500000}, +{(float)-0.681718, (float)0.147621, (float)-0.716567}, +{(float)-0.681718, (float)-0.147621, (float)-0.716567}, +{(float)-0.850651, (float)0.000000, (float)-0.525731}, +{(float)-0.688191, (float)0.587785, (float)-0.425325}, +{(float)-0.587785, (float)0.425325, (float)-0.688191}, +{(float)-0.425325, (float)0.688191, (float)-0.587785}, +{(float)-0.425325, (float)-0.688191, (float)-0.587785}, +{(float)-0.587785, (float)-0.425325, (float)-0.688191}, +{(float)-0.688191, (float)-0.587785, (float)-0.425325}, diff --git a/project/jni/application/quake/source/bspfile.h b/project/jni/application/quake/source/bspfile.h new file mode 100644 index 000000000..9d05b23e2 --- /dev/null +++ b/project/jni/application/quake/source/bspfile.h @@ -0,0 +1,333 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + + +// upper design bounds + +#define MAX_MAP_HULLS 4 + +#define MAX_MAP_MODELS 256 +#define MAX_MAP_BRUSHES 4096 +#define MAX_MAP_ENTITIES 1024 +#define MAX_MAP_ENTSTRING 65536 + +#define MAX_MAP_PLANES 32767 +#define MAX_MAP_NODES 32767 // because negative shorts are contents +#define MAX_MAP_CLIPNODES 32767 // +#define MAX_MAP_LEAFS 8192 +#define MAX_MAP_VERTS 65535 +#define MAX_MAP_FACES 65535 +#define MAX_MAP_MARKSURFACES 65535 +#define MAX_MAP_TEXINFO 4096 +#define MAX_MAP_EDGES 256000 +#define MAX_MAP_SURFEDGES 512000 +#define MAX_MAP_TEXTURES 512 +#define MAX_MAP_MIPTEX 0x200000 +#define MAX_MAP_LIGHTING 0x100000 +#define MAX_MAP_VISIBILITY 0x100000 + +#define MAX_MAP_PORTALS 65536 + +// key / value pair sizes + +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +//============================================================================= + + +#define BSPVERSION 29 +#define TOOLVERSION 2 + +typedef struct +{ + int fileofs, filelen; +} lump_t; + +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_TEXTURES 2 +#define LUMP_VERTEXES 3 +#define LUMP_VISIBILITY 4 +#define LUMP_NODES 5 +#define LUMP_TEXINFO 6 +#define LUMP_FACES 7 +#define LUMP_LIGHTING 8 +#define LUMP_CLIPNODES 9 +#define LUMP_LEAFS 10 +#define LUMP_MARKSURFACES 11 +#define LUMP_EDGES 12 +#define LUMP_SURFEDGES 13 +#define LUMP_MODELS 14 + +#define HEADER_LUMPS 15 + +typedef struct +{ + float mins[3], maxs[3]; + float origin[3]; + int headnode[MAX_MAP_HULLS]; + int visleafs; // not including the solid leaf 0 + int firstface, numfaces; +} dmodel_t; +/* +typedef struct +{ + fixedpoint_t mins[3], maxs[3]; + fixedpoint_t origin[3]; + int headnode[MAX_MAP_HULLS]; + int visleafs; // not including the solid leaf 0 + int firstface, numfaces; +} dmodel_FPM_t; +*/ +typedef struct +{ + int version; + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + int nummiptex; + int dataofs[4]; // [nummiptex] +} dmiptexlump_t; + +#define MIPLEVELS 4 +typedef struct miptex_s +{ + char name[16]; + unsigned width, height; + unsigned offsets[MIPLEVELS]; // four mip maps stored +} miptex_t; + + +typedef struct +{ + float point[3]; +} dvertex_t; + + +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 + +// 3-5 are non-axial planes snapped to the nearest +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +typedef struct +{ + float normal[3]; + float dist; + int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate +} dplane_t; + + + +#define CONTENTS_EMPTY -1 +#define CONTENTS_SOLID -2 +#define CONTENTS_WATER -3 +#define CONTENTS_SLIME -4 +#define CONTENTS_LAVA -5 +#define CONTENTS_SKY -6 +#define CONTENTS_ORIGIN -7 // removed at csg time +#define CONTENTS_CLIP -8 // changed to contents_solid + +#define CONTENTS_CURRENT_0 -9 +#define CONTENTS_CURRENT_90 -10 +#define CONTENTS_CURRENT_180 -11 +#define CONTENTS_CURRENT_270 -12 +#define CONTENTS_CURRENT_UP -13 +#define CONTENTS_CURRENT_DOWN -14 + + +// !!! if this is changed, it must be changed in asm_i386.h too !!! +typedef struct +{ + int planenum; + short children[2]; // negative numbers are -(leafs+1), not nodes + short mins[3]; // for sphere culling + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; // counting both sides +} dnode_t; + +typedef struct +{ + int planenum; + short children[2]; // negative numbers are contents +} dclipnode_t; + + +typedef struct texinfo_s +{ + float vecs[2][4]; // [s/t][xyz offset] + int miptex; + int flags; +} texinfo_t; +#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision + +// note that edge 0 is never used, because negative edge nums are used for +// counterclockwise use of the edge in a face +typedef struct +{ + unsigned short v[2]; // vertex numbers +} dedge_t; + +#define MAXLIGHTMAPS 4 +typedef struct +{ + short planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + +// lighting info + byte styles[MAXLIGHTMAPS]; + int lightofs; // start of [numstyles*surfsize] samples +} dface_t; + + + +#define AMBIENT_WATER 0 +#define AMBIENT_SKY 1 +#define AMBIENT_SLIME 2 +#define AMBIENT_LAVA 3 + +#define NUM_AMBIENTS 4 // automatic ambient sounds + +// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas +// all other leafs need visibility info +typedef struct +{ + int contents; + int visofs; // -1 = no visibility info + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstmarksurface; + unsigned short nummarksurfaces; + + byte ambient_level[NUM_AMBIENTS]; +} dleaf_t; + + +//============================================================================ + +#ifndef QUAKE_GAME + +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + + +// the utilities get to be lazy and just use large static arrays + +extern int nummodels; +extern dmodel_t dmodels[MAX_MAP_MODELS]; + +extern int visdatasize; +extern byte dvisdata[MAX_MAP_VISIBILITY]; + +extern int lightdatasize; +extern byte dlightdata[MAX_MAP_LIGHTING]; + +extern int texdatasize; +extern byte dtexdata[MAX_MAP_MIPTEX]; // (dmiptexlump_t) + +extern int entdatasize; +extern char dentdata[MAX_MAP_ENTSTRING]; + +extern int numleafs; +extern dleaf_t dleafs[MAX_MAP_LEAFS]; + +extern int numplanes; +extern dplane_t dplanes[MAX_MAP_PLANES]; + +extern int numvertexes; +extern dvertex_t dvertexes[MAX_MAP_VERTS]; + +extern int numnodes; +extern dnode_t dnodes[MAX_MAP_NODES]; + +extern int numtexinfo; +extern texinfo_t texinfo[MAX_MAP_TEXINFO]; + +extern int numfaces; +extern dface_t dfaces[MAX_MAP_FACES]; + +extern int numclipnodes; +extern dclipnode_t dclipnodes[MAX_MAP_CLIPNODES]; + +extern int numedges; +extern dedge_t dedges[MAX_MAP_EDGES]; + +extern int nummarksurfaces; +extern unsigned short dmarksurfaces[MAX_MAP_MARKSURFACES]; + +extern int numsurfedges; +extern int dsurfedges[MAX_MAP_SURFEDGES]; + + +void DecompressVis (byte *in, byte *decompressed); +int CompressVis (byte *vis, byte *dest); + +void LoadBSPFile (char *filename); +void WriteBSPFile (char *filename); +void PrintBSPFileSizes (void); + +//=============== + + +typedef struct epair_s +{ + struct epair_s *next; + char *key; + char *value; +} epair_t; + +typedef struct +{ + vec3_t origin; + int firstbrush; + int numbrushes; + epair_t *epairs; +} entity_t; + +extern int num_entities; +extern entity_t entities[MAX_MAP_ENTITIES]; + +void ParseEntities (void); +void UnparseEntities (void); + +void SetKeyValue (entity_t *ent, char *key, char *value); +char *ValueForKey (entity_t *ent, char *key); +// will return "" if not present + +vec_t FloatForKey (entity_t *ent, char *key); +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec); + +epair_t *ParseEpair (void); + +#endif diff --git a/project/jni/application/quake/source/cd_null.c b/project/jni/application/quake/source/cd_null.c new file mode 100644 index 000000000..d5eeec8ad --- /dev/null +++ b/project/jni/application/quake/source/cd_null.c @@ -0,0 +1,55 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "quakedef.h" + +void CDAudio_Play(byte track, qboolean looping) +{ +} + + +void CDAudio_Stop(void) +{ +} + + +void CDAudio_Pause(void) +{ +} + + +void CDAudio_Resume(void) +{ +} + + +void CDAudio_Update(void) +{ +} + + +int CDAudio_Init(void) +{ + return 0; +} + + +void CDAudio_Shutdown(void) +{ +} \ No newline at end of file diff --git a/project/jni/application/quake/source/cdaudio.h b/project/jni/application/quake/source/cdaudio.h new file mode 100644 index 000000000..a29b9d62b --- /dev/null +++ b/project/jni/application/quake/source/cdaudio.h @@ -0,0 +1,33 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +unsigned int * musicPos; +unsigned int musicFilePos; +unsigned char musicBuffer[32768]; +//F_HANDLE music_fh; +int block_in; + +int CDAudio_Init(void); +void CDAudio_Play(byte track, qboolean looping); +void CDAudio_Stop(void); +void CDAudio_Pause(void); +void CDAudio_Resume(void); +void CDAudio_Shutdown(void); +void CDAudio_Update(void); diff --git a/project/jni/application/quake/source/chase.c b/project/jni/application/quake/source/chase.c new file mode 100644 index 000000000..59b886183 --- /dev/null +++ b/project/jni/application/quake/source/chase.c @@ -0,0 +1,149 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// chase.c -- chase camera code + +#include "quakedef.h" + +cvar_t chase_back = {"chase_back", "100"}; +cvar_t chase_up = {"chase_up", "16"}; +cvar_t chase_right = {"chase_right", "0"}; +cvar_t chase_active = {"chase_active", "0"}; + +vec3_t chase_pos; +vec3_t chase_angles; + +vec3_t chase_dest; +vec3_t chase_dest_angles; + +#ifdef USEFPM +vec3_FPM_t chase_posFPM; +vec3_FPM_t chase_anglesFPM; + +vec3_FPM_t chase_destFPM; +vec3_FPM_t chase_dest_anglesFPM; +#endif + +void Chase_Init (void) +{ + Cvar_RegisterVariable (&chase_back); + Cvar_RegisterVariable (&chase_up); + Cvar_RegisterVariable (&chase_right); + Cvar_RegisterVariable (&chase_active); +} + +void Chase_Reset (void) +{ + // for respawning and teleporting +// start position 12 units behind head +} + +//Dan: Added forward declaration to prevent compiler warning +qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace); + +void TraceLine (vec3_t start, vec3_t end, vec3_t impact) +{ + trace_t trace; + + Q_memset (&trace, 0, sizeof(trace)); + SV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace); + + VectorCopy (trace.endpos, impact); +} + +#ifdef USEFPM +void TraceLineFPM (vec3_FPM_t start, vec3_FPM_t end, vec3_FPM_t impact) +{ + trace_FPM_t trace; + + Q_memset (&trace, 0, sizeof(trace)); + //Dan: TODO: This links us to the world of networked quake... + //SV_RecursiveHullCheckFPM (clFPM.worldmodel->hulls, 0, 0, 1, start, end, &trace); + + VectorCopy (trace.endpos, impact); +} +#endif + +void Chase_Update (void) +{ + int i; + float dist; + vec3_t forward, up, right; + vec3_t dest, stop; + + + // if can't see player, reset + AngleVectors (cl.viewangles, forward, right, up); + + // calc exact destination + for (i=0 ; i<3 ; i++) + chase_dest[i] = r_refdef.vieworg[i] + - forward[i]*chase_back.value + - right[i]*chase_right.value; + chase_dest[2] = r_refdef.vieworg[2] + chase_up.value; + + // find the spot the player is looking at + VectorMA (r_refdef.vieworg, 4096, forward, dest); + TraceLine (r_refdef.vieworg, dest, stop); + + // calculate pitch to look at the same spot from camera + VectorSubtract (stop, r_refdef.vieworg, stop); + dist = DotProduct (stop, forward); + if (dist < 1) + dist = 1; + r_refdef.viewangles[PITCH] = (float)(-atan(stop[2] / dist) / M_PI * 180); + + // move towards destination + VectorCopy (chase_dest, r_refdef.vieworg); +} + +#ifdef USEFPM +void Chase_UpdateFPM (void) +{ + int i; + fixedpoint_t dist; + vec3_FPM_t forward, up, right; + vec3_FPM_t dest, stop; + + + // if can't see player, reset + AngleVectorsFPM (clFPM.viewangles, forward, right, up); + + // calc exact destination + for (i=0 ; i<3 ; i++) + chase_destFPM[i] = FPM_SUB(FPM_SUB(r_refdefFPM.vieworg[i], + FPM_MUL(forward[i],FPM_FROMFLOAT(chase_back.value))), + FPM_MUL(right[i],FPM_FROMFLOAT(chase_right.value))); + chase_destFPM[2] = FPM_ADD(r_refdefFPM.vieworg[2], FPM_FROMFLOAT(chase_up.value)); + + // find the spot the player is looking at + VectorMAFPM (r_refdefFPM.vieworg, FPM_FROMLONG(4096), forward, dest); + TraceLineFPM (r_refdefFPM.vieworg, dest, stop); + + // calculate pitch to look at the same spot from camera + VectorSubtractFPM (stop, r_refdefFPM.vieworg, stop); + dist = DotProductFPM (stop, forward); + if (dist < FPM_FROMLONG(1)) + dist = FPM_FROMLONG(1); + r_refdefFPM.viewangles[PITCH] = -FPM_MUL(FPM_DIV(FPM_ATAN(FPM_DIV(stop[2], dist)), FPM_PI), FPM_FROMLONG(180)); + + // move towards destination + VectorCopy (chase_destFPM, r_refdefFPM.vieworg); +} +#endif diff --git a/project/jni/application/quake/source/cl_demo.c b/project/jni/application/quake/source/cl_demo.c new file mode 100644 index 000000000..d9072a619 --- /dev/null +++ b/project/jni/application/quake/source/cl_demo.c @@ -0,0 +1,475 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" + +//Dan +//#include "../zlib/zlib.h" +#ifdef _X86_ +#include "../LogFloat.h" +#endif + +void CL_FinishTimeDemo (void); + +/* +============================================================================== + +DEMO CODE + +When a demo is playing back, all NET_SendMessages are skipped, and +NET_GetMessages are read from the demo file. + +Whenever cl.time gets past the last received message, another message is +read from the demo file. +============================================================================== +*/ + +/* +============== +CL_StopPlayback + +Called when a demo file runs out, or the user starts a game +============== +*/ +void CL_StopPlayback (void) +{ + if (!cls.demoplayback) + return; + + //Dan: + fclose (cls.demofile); + cls.demoplayback = false; + cls.demofile = NULL; + cls.state = ca_disconnected; + + if (cls.timedemo) + CL_FinishTimeDemo (); +} + +/* +==================== +CL_WriteDemoMessage + +Dumps the current net message, prefixed by the length and view angles +==================== +*/ +void CL_WriteDemoMessage (void) +{ + int len; + int i; + float f; + + len = LittleLong (net_message.cursize); + fwrite (&len, 4, 1, cls.demofile); + for (i=0 ; i<3 ; i++) + { + f = LittleFloat (cl.viewangles[i]); + fwrite (&f, 4, 1, cls.demofile); + } + fwrite (net_message.data, net_message.cursize, 1, cls.demofile); + fflush (cls.demofile); +} + +/* +==================== +CL_GetMessage + +Handles recording and playback of demos, on top of NET_ code +==================== +*/ +int CL_GetMessage (void) +{ + int r, i; + float f; + + if (cls.demoplayback) + { + // decide if it is time to grab the next message + if (cls.signon == SIGNONS) // allways grab until fully connected + { + if (cls.timedemo) + { + if (host_framecount == cls.td_lastframe) + return 0; // allready read this frame's message + cls.td_lastframe = host_framecount; + // if this is the second frame, grab the real td_starttime + // so the bogus time on the first frame doesn't count + if (host_framecount == cls.td_startframe + 1) + cls.td_starttime = (float)realtime; + } + else if ( /* cl.time > 0 && */ cl.time <= cl.mtime[0]) + { + return 0; // don't need another message yet + } + } + + // get the next message + fread (&net_message.cursize, 4, 1, cls.demofile); + VectorCopy (cl.mviewangles[0], cl.mviewangles[1]); + for (i=0 ; i<3 ; i++) + { + r = fread (&f, 4, 1, cls.demofile); + cl.mviewangles[0][i] = LittleFloat (f); + } + + net_message.cursize = LittleLong (net_message.cursize); + if (net_message.cursize > MAX_MSGLEN) + Sys_Error ("Demo message > MAX_MSGLEN"); + r = fread (net_message.data, net_message.cursize, 1, cls.demofile); + if (r != /*net_message.cursize*/1) + { + CL_StopPlayback (); + return 0; + } + + return 1; + } + + while (1) + { + r = NET_GetMessage (cls.netcon); + + if (r != 1 && r != 2) + return r; + + // discard nop keepalive message + if (net_message.cursize == 1 && net_message.data[0] == svc_nop) + Con_Printf ("<-- server to client keepalive\n"); + else + break; + } + + if (cls.demorecording) + CL_WriteDemoMessage (); + + return r; +} + +#ifdef USEFPM +int CL_GetMessageFPM (void) +{ + int r, i; + float f; + + if (cls.demoplayback) + { + // decide if it is time to grab the next message + if (cls.signon == SIGNONS) // allways grab until fully connected + { + if (cls.timedemo) + { + if (host_framecount == cls.td_lastframe) + return 0; // allready read this frame's message + cls.td_lastframe = host_framecount; + // if this is the second frame, grab the real td_starttime + // so the bogus time on the first frame doesn't count + if (host_framecount == cls.td_startframe + 1) + cls.td_starttime = (float)realtime; + } + else if ( /* cl.time > 0 && */ clFPM.time <= clFPM.mtime[0]) + { + return 0; // don't need another message yet + } + } + + // get the next message + //Dan + fread (&net_message.cursize, 4, 1, cls.demofile); + VectorCopy (clFPM.mviewangles[0], clFPM.mviewangles[1]); + for (i=0 ; i<3 ; i++) + { + //Dan + r = fread (&f, 4, 1, cls.demofile); + clFPM.mviewangles[0][i] = FPM_FROMFLOAT(LittleFloat (f)); + } + + net_message.cursize = LittleLong (net_message.cursize); + if (net_message.cursize > MAX_MSGLEN) + Sys_Error ("Demo message > MAX_MSGLEN"); + //Dan + r = fread (net_message.data, net_message.cursize, 1, cls.demofile); + if (r != net_message.cursize/*1*/) + { + CL_StopPlayback (); + return 0; + } + + return 1; + } + + while (1) + { + r = NET_GetMessage (cls.netcon); + + if (r != 1 && r != 2) + return r; + + // discard nop keepalive message + if (net_message.cursize == 1 && net_message.data[0] == svc_nop) + Con_Printf ("<-- server to client keepalive\n"); + else + break; + } + + if (cls.demorecording) + CL_WriteDemoMessage (); + + return r; +} +#endif +/* +==================== +CL_Stop_f + +stop recording a demo +==================== +*/ +void CL_Stop_f (void) +{ + if (cmd_source != src_command) + return; + + if (!cls.demorecording) + { + Con_Printf ("Not recording a demo.\n"); + return; + } + +// write a disconnect message to the demo file + SZ_Clear (&net_message); + MSG_WriteByte (&net_message, svc_disconnect); + CL_WriteDemoMessage (); + +// finish up + fclose (cls.demofile); + cls.demofile = NULL; + cls.demorecording = false; + Con_Printf ("Completed demo\n"); +} + +/* +==================== +CL_Record_f + +record [cd track] +==================== +*/ +void CL_Record_f (void) +{ + int c; + char name[MAX_OSPATH]; + int track; + + if (cmd_source != src_command) + return; + + c = Cmd_Argc(); + if (c != 2 && c != 3 && c != 4) + { + Con_Printf ("record [ [cd track]]\n"); + return; + } + + if (strstr(Cmd_Argv(1), "..")) + { + Con_Printf ("Relative pathnames are not allowed.\n"); + return; + } + + if (c == 2 && cls.state == ca_connected) + { + Con_Printf("Can not record - already connected to server\nClient demo recording must be started before connecting\n"); + return; + } + +// write the forced cd track number, or -1 + if (c == 4) + { + track = atoi(Cmd_Argv(3)); + Con_Printf ("Forcing CD track to %i\n", cls.forcetrack); + } + else + track = -1; + + sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); + +// +// start the map up +// + if (c > 2) + Cmd_ExecuteString ( va("map %s", Cmd_Argv(2)), src_command); + +// +// open the demo file +// + COM_DefaultExtension (name, ".dem"); + + Con_Printf ("recording to %s.\n", name); + cls.demofile = fopen (name, "wb"); + if (!cls.demofile) + { + Con_Printf ("ERROR: couldn't open.\n"); + return; + } + + cls.forcetrack = track; + fprintf (cls.demofile, "%i\n", cls.forcetrack); + + cls.demorecording = true; +} + + +// Demos disabled at start to allow game to play. Playdemo command remapped to gpplaydemo so this function allows for silent fail of playdemo command. + +void CL_PlayDemo_silentfail (void) +{ + +} + + +/* +==================== +CL_PlayDemo_f + +play [demoname] +==================== +*/ +void CL_PlayDemo_f (void) +{ + char name[256]; + int c; + qboolean neg = false; + + + if (cmd_source != src_command) + return; + + if (Cmd_Argc() != 2) + { + Con_Printf ("play : plays a demo\n"); + return; + } + +// +// disconnect from server +// +#ifndef USEFPM + CL_Disconnect (); +#else + CL_DisconnectFPM (); +#endif + +// +// open the demo file +// + strcpy (name, Cmd_Argv(1)); + COM_DefaultExtension (name, ".dem"); + + Con_Printf ("Playing demo from %s.\n", name); + COM_FOpenFile (name, &cls.demofile); + if (!cls.demofile) + { + Con_Printf ("ERROR: couldn't open.\n"); + cls.demonum = -1; // stop demo loop + return; + } + + cls.demoplayback = true; + cls.state = ca_connected; + cls.forcetrack = 0; + + while ((c = fgetc(cls.demofile)) != '\n') + if (c == '-') + neg = true; + else + cls.forcetrack = cls.forcetrack * 10 + (c - '0'); + + if (neg) + cls.forcetrack = -cls.forcetrack; +// ZOID, fscanf is evil +// fscanf (cls.demofile, "%i\n", &cls.forcetrack); +} + +/* +==================== +CL_FinishTimeDemo + +==================== +*/ +void CL_FinishTimeDemo (void) +{ + int frames; + float time; + + cls.timedemo = false; + +// the first frame didn't count + frames = (host_framecount - cls.td_startframe) - 1; + time = (float)(realtime - cls.td_starttime); + if (!time) + time = 1; + Con_Printf ("%i frames %5.1f seconds %5.1f fps\n", frames, time, frames/time); + +#ifdef _X86_ + //Dan East: + //The following generates Floating Point totals if floating point logging was performed + LogFloatResults("\\LogFloat.txt"); +#endif +/* + //Dan East: + //The following is used to popup a message box with the timedemo results. + //The purpose of this is to make the results known when screen output is + //disabled (in the case of various benchmark testing). + { + TCHAR s[250]; + _stprintf(s, _T("%i frames %5.1f seconds %5.1f fps\n"), frames, time, frames/time); + MessageBox(NULL, s, _T("TimeDemo Results"), MB_OK); + } +*/ +} + +/* +==================== +CL_TimeDemo_f + +timedemo [demoname] +==================== +*/ +void CL_TimeDemo_f (void) +{ + if (cmd_source != src_command) + return; + + if (Cmd_Argc() != 2) + { + Con_Printf ("timedemo : gets demo speeds\n"); + return; + } + + CL_PlayDemo_f (); + +// cls.td_starttime will be grabbed at the second frame of the demo, so +// all the loading time doesn't get counted + + cls.timedemo = true; + cls.td_startframe = host_framecount; + cls.td_lastframe = -1; // get a new message this frame +} + diff --git a/project/jni/application/quake/source/cl_input.c b/project/jni/application/quake/source/cl_input.c new file mode 100644 index 000000000..ffb777cbe --- /dev/null +++ b/project/jni/application/quake/source/cl_input.c @@ -0,0 +1,649 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cl.input.c -- builds an intended movement command to send to the server + +// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All +// rights reserved. + +#include "quakedef.h" + +/* +=============================================================================== + +KEY BUTTONS + +Continuous button event tracking is complicated by the fact that two different +input sources (say, mouse button 1 and the control key) can both press the +same button, but the button should only be released when both of the +pressing key have been released. + +When a key event issues a button command (+forward, +attack, etc), it appends +its key number as a parameter to the command so it can be matched up with +the release. + +state bit 0 is the current state of the key +state bit 1 is edge triggered on the up to down transition +state bit 2 is edge triggered on the down to up transition + +=============================================================================== +*/ + + +kbutton_t in_mlook, in_klook; +kbutton_t in_left, in_right, in_forward, in_back; +kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright; +kbutton_t in_strafe, in_speed, in_use, in_jump, in_attack; +kbutton_t in_up, in_down; + +int in_impulse; + + +void KeyDown (kbutton_t *b) +{ + int k; + char *c; + + c = Cmd_Argv(1); + if (c[0]) + k = atoi(c); + else + k = -1; // typed manually at the console for continuous down + + if (k == b->down[0] || k == b->down[1]) + return; // repeating key + + if (!b->down[0]) + b->down[0] = k; + else if (!b->down[1]) + b->down[1] = k; + else + { + Con_Printf ("Three keys down for a button!\n"); + return; + } + + if (b->state & 1) + return; // still down + b->state |= 1 + 2; // down + impulse down +} + +void KeyUp (kbutton_t *b) +{ + int k; + char *c; + + c = Cmd_Argv(1); + if (c[0]) + k = atoi(c); + else + { // typed manually at the console, assume for unsticking, so clear all + b->down[0] = b->down[1] = 0; + b->state = 4; // impulse up + return; + } + + if (b->down[0] == k) + b->down[0] = 0; + else if (b->down[1] == k) + b->down[1] = 0; + else + return; // key up without coresponding down (menu pass through) + if (b->down[0] || b->down[1]) + return; // some other key is still holding it down + + if (!(b->state & 1)) + return; // still up (this should not happen) + b->state &= ~1; // now up + b->state |= 4; // impulse up +} + +void IN_KLookDown (void) {KeyDown(&in_klook);} +void IN_KLookUp (void) {KeyUp(&in_klook);} +void IN_MLookDown (void) {KeyDown(&in_mlook);} +void IN_MLookUp (void) { +KeyUp(&in_mlook); +if ( !(in_mlook.state&1) && lookspring.value) + V_StartPitchDrift(); +} +void IN_UpDown(void) {KeyDown(&in_up);} +void IN_UpUp(void) {KeyUp(&in_up);} +void IN_DownDown(void) {KeyDown(&in_down);} +void IN_DownUp(void) {KeyUp(&in_down);} +void IN_LeftDown(void) {KeyDown(&in_left);} +void IN_LeftUp(void) {KeyUp(&in_left);} +void IN_RightDown(void) {KeyDown(&in_right);} +void IN_RightUp(void) {KeyUp(&in_right);} +void IN_ForwardDown(void) {KeyDown(&in_forward);} +void IN_ForwardUp(void) {KeyUp(&in_forward);} +void IN_BackDown(void) {KeyDown(&in_back);} +void IN_BackUp(void) {KeyUp(&in_back);} +void IN_LookupDown(void) {KeyDown(&in_lookup);} +void IN_LookupUp(void) {KeyUp(&in_lookup);} +void IN_LookdownDown(void) {KeyDown(&in_lookdown);} +void IN_LookdownUp(void) {KeyUp(&in_lookdown);} +void IN_MoveleftDown(void) {KeyDown(&in_moveleft);} +void IN_MoveleftUp(void) {KeyUp(&in_moveleft);} +void IN_MoverightDown(void) {KeyDown(&in_moveright);} +void IN_MoverightUp(void) {KeyUp(&in_moveright);} + +void IN_SpeedDown(void) {KeyDown(&in_speed);} +void IN_SpeedUp(void) {KeyUp(&in_speed);} +void IN_StrafeDown(void) {KeyDown(&in_strafe);} +void IN_StrafeUp(void) {KeyUp(&in_strafe);} + +void IN_AttackDown(void) {KeyDown(&in_attack);} +void IN_AttackUp(void) {KeyUp(&in_attack);} + +void IN_UseDown (void) {KeyDown(&in_use);} +void IN_UseUp (void) {KeyUp(&in_use);} +void IN_JumpDown (void) {KeyDown(&in_jump);} +void IN_JumpUp (void) {KeyUp(&in_jump);} + +void IN_Impulse (void) {in_impulse=Q_atoi(Cmd_Argv(1));} + +/* +=============== +CL_KeyState + +Returns 0.25 if a key was pressed and released during the frame, +0.5 if it was pressed and held +0 if held then released, and +1.0 if held for the entire time +=============== +*/ +float CL_KeyState (kbutton_t *key) +{ + float val; + qboolean impulsedown, impulseup, down; + + impulsedown = key->state & 2; + impulseup = key->state & 4; + down = key->state & 1; + val = 0; + + if (impulsedown && !impulseup) + if (down) + val = 0.5; // pressed and held this frame + else + val = 0; // I_Error (); + if (impulseup && !impulsedown) + if (down) + val = 0; // I_Error (); + else + val = 0; // released this frame + if (!impulsedown && !impulseup) + if (down) + val = 1.0; // held the entire frame + else + val = 0; // up the entire frame + if (impulsedown && impulseup) + if (down) + val = 0.75; // released and re-pressed this frame + else + val = 0.25; // pressed and released this frame + + key->state &= 1; // clear impulses + + return val; +} + +#ifdef USEFPM +fixedpoint_t CL_KeyStateFPM (kbutton_t *key) +{ + fixedpoint_t val; + qboolean impulsedown, impulseup, down; + + impulsedown = key->state & 2; + impulseup = key->state & 4; + down = key->state & 1; + val = 0; + + if (impulsedown && !impulseup) + if (down) + val = FPM_FROMFLOATC(0.5); // pressed and held this frame + else + val = 0; // I_Error (); + if (impulseup && !impulsedown) + if (down) + val = 0; // I_Error (); + else + val = 0; // released this frame + if (!impulsedown && !impulseup) + if (down) + val = FPM_FROMFLOATC(1.0); // held the entire frame + else + val = 0; // up the entire frame + if (impulsedown && impulseup) + if (down) + val = FPM_FROMFLOATC(0.75); // released and re-pressed this frame + else + val = FPM_FROMFLOATC(0.25); // pressed and released this frame + + key->state &= 1; // clear impulses + + return val; +} +#endif + + +//========================================================================== + +cvar_t cl_upspeed = {"cl_upspeed","200"}; +cvar_t cl_forwardspeed = {"cl_forwardspeed","200", true}; +cvar_t cl_backspeed = {"cl_backspeed","200", true}; +cvar_t cl_sidespeed = {"cl_sidespeed","350"}; + +cvar_t cl_movespeedkey = {"cl_movespeedkey","2.0"}; + +cvar_t cl_yawspeed = {"cl_yawspeed","140"}; +cvar_t cl_pitchspeed = {"cl_pitchspeed","150"}; + +cvar_t cl_anglespeedkey = {"cl_anglespeedkey","1.5"}; + + +/* +================ +CL_AdjustAngles + +Moves the local angle positions +================ +*/ +void CL_AdjustAngles (void) +{ + float speed; + float up, down; + + if (in_speed.state & 1) + speed = (float)(host_frametime * cl_anglespeedkey.value); + else + speed = (float)host_frametime; + + if (!(in_strafe.state & 1)) + { + cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right); + cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left); + cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]); + } + if (in_klook.state & 1) + { + V_StopPitchDrift (); + cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward); + cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back); + } + + up = CL_KeyState (&in_lookup); + down = CL_KeyState(&in_lookdown); + + cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up; + cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down; + + if (up || down) + V_StopPitchDrift (); + + if (cl.viewangles[PITCH] > 80) + cl.viewangles[PITCH] = 80; + if (cl.viewangles[PITCH] < -70) + cl.viewangles[PITCH] = -70; + + if (cl.viewangles[ROLL] > 50) + cl.viewangles[ROLL] = 50; + if (cl.viewangles[ROLL] < -50) + cl.viewangles[ROLL] = -50; + +} + +#ifdef USEFPM +void CL_AdjustAnglesFPM (void) +{ + fixedpoint_t speed; + fixedpoint_t up, down; + fixedpoint_t clpitchspeed=FPM_FROMFLOAT(cl_pitchspeed.value); + + if (in_speed.state & 1) + speed = FPM_FROMFLOAT(host_frametime * cl_anglespeedkey.value); + else + speed = FPM_FROMFLOAT(host_frametime); + + if (!(in_strafe.state & 1)) + { + fixedpoint_t clyawspeed=FPM_FROMFLOAT(cl_yawspeed.value); + clFPM.viewangles[YAW] = FPM_SUB(clFPM.viewangles[YAW], FPM_MUL(FPM_MUL(speed,clyawspeed), CL_KeyStateFPM (&in_right))); + clFPM.viewangles[YAW] = FPM_ADD(clFPM.viewangles[YAW], FPM_MUL(FPM_MUL(speed,clyawspeed), CL_KeyStateFPM (&in_left))); + clFPM.viewangles[YAW] = anglemodFPM(clFPM.viewangles[YAW]); + } + if (in_klook.state & 1) + { + V_StopPitchDriftFPM (); + clFPM.viewangles[PITCH] = FPM_SUB(clFPM.viewangles[PITCH], FPM_MUL(FPM_MUL(speed,clpitchspeed), CL_KeyStateFPM (&in_forward))); + clFPM.viewangles[PITCH] = FPM_ADD(clFPM.viewangles[PITCH], FPM_MUL(FPM_MUL(speed,clpitchspeed), CL_KeyStateFPM (&in_back))); + } + + up = CL_KeyStateFPM (&in_lookup); + down = CL_KeyStateFPM(&in_lookdown); + + clFPM.viewangles[PITCH] = FPM_SUB(clFPM.viewangles[PITCH], FPM_MUL(FPM_MUL(speed, clpitchspeed), up)); + clFPM.viewangles[PITCH] = FPM_ADD(clFPM.viewangles[PITCH], FPM_MUL(FPM_MUL(speed, clpitchspeed), down)); + + if (up || down) + V_StopPitchDriftFPM (); + + if (clFPM.viewangles[PITCH] > FPM_FROMLONGC(80)) + clFPM.viewangles[PITCH] = FPM_FROMLONGC(80); + if (clFPM.viewangles[PITCH] < FPM_FROMLONGC(-70)) + clFPM.viewangles[PITCH] = FPM_FROMLONGC(-70); + + if (clFPM.viewangles[ROLL] > FPM_FROMLONGC(50)) + clFPM.viewangles[ROLL] = FPM_FROMLONGC(50); + if (clFPM.viewangles[ROLL] < FPM_FROMLONGC(-50)) + clFPM.viewangles[ROLL] = FPM_FROMLONGC(-50); + +} +#endif + +/* +================ +CL_BaseMove + +Send the intended movement message to the server +================ +*/ +void CL_BaseMove (usercmd_t *cmd) +{ + if (cls.signon != SIGNONS) + return; + + CL_AdjustAngles (); + + Q_memset (cmd, 0, sizeof(*cmd)); + + if (in_strafe.state & 1) + { + cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right); + cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left); + } + + cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright); + cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft); + + cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up); + cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down); + + if (! (in_klook.state & 1) ) + { + cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward); + cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back); + } + +// +// adjust for speed key +// + if (in_speed.state & 1) + { + cmd->forwardmove *= cl_movespeedkey.value; + cmd->sidemove *= cl_movespeedkey.value; + cmd->upmove *= cl_movespeedkey.value; + } + +#ifdef QUAKE2 + cmd->lightlevel = cl.light_level; +#endif +} + +#ifdef USEFPM +void CL_BaseMoveFPM (usercmd_FPM_t *cmd) +{ + if (cls.signon != SIGNONS) + return; + + CL_AdjustAnglesFPM (); + + Q_memset (cmd, 0, sizeof(*cmd)); + + if (in_strafe.state & 1) + { + cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right); + cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left); + } + + cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright); + cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft); + + cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up); + cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down); + + if (! (in_klook.state & 1) ) + { + cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward); + cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back); + } + +// +// adjust for speed key +// + if (in_speed.state & 1) + { + cmd->forwardmove *= cl_movespeedkey.value; + cmd->sidemove *= cl_movespeedkey.value; + cmd->upmove *= cl_movespeedkey.value; + } + +#ifdef QUAKE2 + cmd->lightlevel = clFPM.light_level; +#endif +} +#endif + +/* +============== +CL_SendMove +============== +*/ +void CL_SendMove (usercmd_t *cmd) +{ + int i; + int bits; + sizebuf_t buf; + byte data[128]; + + buf.maxsize = 128; + buf.cursize = 0; + buf.data = data; + + cl.cmd = *cmd; + +// +// send the movement message +// + MSG_WriteByte (&buf, clc_move); + + MSG_WriteFloat (&buf, (float)cl.mtime[0]); // so server can get ping times + + for (i=0 ; i<3 ; i++) + MSG_WriteAngle (&buf, cl.viewangles[i]); + + MSG_WriteShort (&buf, (int)cmd->forwardmove); + MSG_WriteShort (&buf, (int)cmd->sidemove); + MSG_WriteShort (&buf, (int)cmd->upmove); + +// +// send button bits +// + bits = 0; + + if ( in_attack.state & 3 ) + bits |= 1; + in_attack.state &= ~2; + + if (in_jump.state & 3) + bits |= 2; + in_jump.state &= ~2; + + MSG_WriteByte (&buf, bits); + + MSG_WriteByte (&buf, in_impulse); + in_impulse = 0; + +#ifdef QUAKE2 +// +// light level +// + MSG_WriteByte (&buf, cmd->lightlevel); +#endif + +// +// deliver the message +// + if (cls.demoplayback) + return; + +// +// allways dump the first two message, because it may contain leftover inputs +// from the last level +// + if (++cl.movemessages <= 2) + return; + + if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1) + { + GpError("CL_SendMove, -1",2); + Con_Printf ("CL_SendMove: lost server connection\n"); + CL_Disconnect (); + } + +} + +#ifdef USEFPM +void CL_SendMoveFPM (usercmd_FPM_t *cmd) +{ + int i; + int bits; + sizebuf_t buf; + byte data[128]; + + buf.maxsize = 128; + buf.cursize = 0; + buf.data = data; + + clFPM.cmd = *cmd; + +// +// send the movement message +// + MSG_WriteByte (&buf, clc_move); + + MSG_WriteFloat (&buf, (float)clFPM.mtime[0]); // so server can get ping times + + for (i=0 ; i<3 ; i++) + MSG_WriteAngle (&buf, FPM_TOFLOAT(clFPM.viewangles[i])); + + MSG_WriteShort (&buf, (int)cmd->forwardmove); + MSG_WriteShort (&buf, (int)cmd->sidemove); + MSG_WriteShort (&buf, (int)cmd->upmove); + +// +// send button bits +// + bits = 0; + + if ( in_attack.state & 3 ) + bits |= 1; + in_attack.state &= ~2; + + if (in_jump.state & 3) + bits |= 2; + in_jump.state &= ~2; + + MSG_WriteByte (&buf, bits); + + MSG_WriteByte (&buf, in_impulse); + in_impulse = 0; + +#ifdef QUAKE2 +// +// light level +// + MSG_WriteByte (&buf, cmd->lightlevel); +#endif + +// +// deliver the message +// + if (cls.demoplayback) + return; + +// +// allways dump the first two message, because it may contain leftover inputs +// from the last level +// + if (++cl.movemessages <= 2) + return; + + if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1) + { + Con_Printf ("CL_SendMove: lost server connection\n"); + CL_Disconnect (); + } +} +#endif +/* +============ +CL_InitInput +============ +*/ +void CL_InitInput (void) +{ + Cmd_AddCommand ("+moveup",IN_UpDown); + Cmd_AddCommand ("-moveup",IN_UpUp); + Cmd_AddCommand ("+movedown",IN_DownDown); + Cmd_AddCommand ("-movedown",IN_DownUp); + Cmd_AddCommand ("+left",IN_LeftDown); + Cmd_AddCommand ("-left",IN_LeftUp); + Cmd_AddCommand ("+right",IN_RightDown); + Cmd_AddCommand ("-right",IN_RightUp); + Cmd_AddCommand ("+forward",IN_ForwardDown); + Cmd_AddCommand ("-forward",IN_ForwardUp); + Cmd_AddCommand ("+back",IN_BackDown); + Cmd_AddCommand ("-back",IN_BackUp); + Cmd_AddCommand ("+lookup", IN_LookupDown); + Cmd_AddCommand ("-lookup", IN_LookupUp); + Cmd_AddCommand ("+lookdown", IN_LookdownDown); + Cmd_AddCommand ("-lookdown", IN_LookdownUp); + Cmd_AddCommand ("+strafe", IN_StrafeDown); + Cmd_AddCommand ("-strafe", IN_StrafeUp); + Cmd_AddCommand ("+moveleft", IN_MoveleftDown); + Cmd_AddCommand ("-moveleft", IN_MoveleftUp); + Cmd_AddCommand ("+moveright", IN_MoverightDown); + Cmd_AddCommand ("-moveright", IN_MoverightUp); + Cmd_AddCommand ("+speed", IN_SpeedDown); + Cmd_AddCommand ("-speed", IN_SpeedUp); + Cmd_AddCommand ("+attack", IN_AttackDown); + Cmd_AddCommand ("-attack", IN_AttackUp); + Cmd_AddCommand ("+use", IN_UseDown); + Cmd_AddCommand ("-use", IN_UseUp); + Cmd_AddCommand ("+jump", IN_JumpDown); + Cmd_AddCommand ("-jump", IN_JumpUp); + Cmd_AddCommand ("impulse", IN_Impulse); + Cmd_AddCommand ("+klook", IN_KLookDown); + Cmd_AddCommand ("-klook", IN_KLookUp); + Cmd_AddCommand ("+mlook", IN_MLookDown); + Cmd_AddCommand ("-mlook", IN_MLookUp); + +} + diff --git a/project/jni/application/quake/source/cl_main.c b/project/jni/application/quake/source/cl_main.c new file mode 100644 index 000000000..19220a0d3 --- /dev/null +++ b/project/jni/application/quake/source/cl_main.c @@ -0,0 +1,1277 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cl_main.c -- client main loop + +#include "quakedef.h" + +// we need to declare some mouse variables here, because the menu system +// references them even when on a unix system. + +// R2-Tec +cvar_t command = {"_command", "", true}; + +// these two are not intended to be set directly +cvar_t cl_name = {"_cl_name", "player", true}; +cvar_t cl_color = {"_cl_color", "0", true}; + +cvar_t cl_showfps = {"cl_showfps","0"};// 2001-11-31 FPS display by QuakeForge/Muff +cvar_t cl_shownet = {"cl_shownet","0"}; // can be 0, 1, or 2 +cvar_t cl_nolerp = {"cl_nolerp","0"}; + +cvar_t lookspring = {"lookspring","0", true}; +cvar_t lookstrafe = {"lookstrafe","0", true}; +cvar_t sensitivity = {"sensitivity","3", true}; + +cvar_t m_pitch = {"m_pitch","0.022", true}; +cvar_t m_yaw = {"m_yaw","0.022", true}; +cvar_t m_forward = {"m_forward","1", true}; +cvar_t m_side = {"m_side","0.8", true}; + +cvar_t cl_config = {"cl_config","0"}; + +client_static_t cls; +client_state_t cl; + +#ifdef USEFPM +client_state_FPM_t clFPM; +#endif + +// FIXME: put these on hunk? +efrag_t cl_efrags[MAX_EFRAGS]; +entity_t cl_entities[MAX_EDICTS]; +entity_t cl_static_entities[MAX_STATIC_ENTITIES]; +lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES]; +dlight_t cl_dlights[MAX_DLIGHTS]; + +#ifdef USEFPM +efrag_FPM_t cl_efragsFPM[MAX_EFRAGS]; +entity_FPM_t cl_entitiesFPM[MAX_EDICTS]; +entity_FPM_t cl_static_entitiesFPM[MAX_STATIC_ENTITIES]; +dlight_FPM_t cl_dlightsFPM[MAX_DLIGHTS]; +#endif + +int cl_numvisedicts; +entity_t *cl_visedicts[MAX_VISEDICTS]; +#ifdef USEFPM +entity_FPM_t *cl_visedictsFPM[MAX_VISEDICTS]; +#endif +/* +===================== +CL_ClearState + +===================== +*/ +void CL_ClearState (void) +{ + int i; + + if (!sv.active) + Host_ClearMemory (); + +// wipe the entire cl structure + Q_memset (&cl, 0, sizeof(cl)); + + SZ_Clear (&cls.message); + +// clear other arrays + Q_memset (cl_efrags, 0, sizeof(cl_efrags)); + Q_memset (cl_entities, 0, sizeof(cl_entities)); + Q_memset (cl_dlights, 0, sizeof(cl_dlights)); + Q_memset (cl_lightstyle, 0, sizeof(cl_lightstyle)); + Q_memset (cl_temp_entities, 0, sizeof(cl_temp_entities)); + Q_memset (cl_beams, 0, sizeof(cl_beams)); + +// +// allocate the efrags and chain together into a free list +// + cl.free_efrags = cl_efrags; + for (i=0 ; i>4, ((int)cl_color.value)&15)); + + MSG_WriteByte (&cls.message, clc_stringcmd); + sprintf (str, "spawn %s", cls.spawnparms); + MSG_WriteString (&cls.message, str); + break; + + case 3: + GpError("CL_SignonReply 3",1); + MSG_WriteByte (&cls.message, clc_stringcmd); + MSG_WriteString (&cls.message, "begin"); + Cache_Report (); // print remaining memory + break; + + case 4: + GpError("CL_SignonReply 4",1); + SCR_EndLoadingPlaque (); // allow normal screen updates + break; + } +} + +/* +===================== +CL_NextDemo + +Called to play the next demo in the demo loop +===================== +*/ +void CL_NextDemo (void) +{ + char str[1024]; + + if (cls.demonum == -1) + return; // don't play demos + + SCR_BeginLoadingPlaque (); + + if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS) + { + cls.demonum = 0; + if (!cls.demos[cls.demonum][0]) + { + Con_Printf ("No demos listed with startdemos\n"); + cls.demonum = -1; + return; + } + } + + sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]); + Cbuf_InsertText (str); + cls.demonum++; +} + +/* +============== +CL_PrintEntities_f +============== +*/ +void CL_PrintEntities_f (void) +{ + entity_t *ent; + int i; + + for (i=0,ent=cl_entities ; imodel) + { + Con_Printf ("EMPTY\n"); + continue; + } + Con_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n" + ,ent->model->name,ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]); + } +} + +#ifdef USEFPM +void CL_PrintEntities_FPM_f (void) +{ + entity_FPM_t *ent; + int i; + + for (i=0,ent=cl_entitiesFPM ; imodel) + { + Con_Printf ("EMPTY\n"); + continue; + } + Con_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n" + ,ent->model->name,ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]); + } +} +#endif +/* +=============== +SetPal + +Debugging tool, just flashes the screen +=============== +*/ +void SetPal (int i) +{ +#if 0 + static int old; + byte pal[768]; + int c; + + if (i == old) + return; + old = i; + + if (i==0) + VID_SetPalette (host_basepal); + else if (i==1) + { + for (c=0 ; c<768 ; c+=3) + { + pal[c] = 0; + pal[c+1] = 255; + pal[c+2] = 0; + } + VID_SetPalette (pal); + } + else + { + for (c=0 ; c<768 ; c+=3) + { + pal[c] = 0; + pal[c+1] = 0; + pal[c+2] = 255; + } + VID_SetPalette (pal); + } +#endif +} + +/* +=============== +CL_AllocDlight + +=============== +*/ +dlight_t *CL_AllocDlight (int key) +{ + int i; + dlight_t *dl; + +// first look for an exact key match + if (key) + { + dl = cl_dlights; + for (i=0 ; ikey == key) + { + Q_memset (dl, 0, sizeof(*dl)); + dl->key = key; + return dl; + } + } + } + +// then look for anything else + dl = cl_dlights; + for (i=0 ; idie < cl.time) + { + Q_memset (dl, 0, sizeof(*dl)); + dl->key = key; + return dl; + } + } + + dl = &cl_dlights[0]; + Q_memset (dl, 0, sizeof(*dl)); + dl->key = key; + return dl; +} + +#ifdef USEFPM +dlight_FPM_t *CL_AllocDlightFPM (int key) +{ + int i; + dlight_FPM_t *dl; + +// first look for an exact key match + if (key) + { + dl = cl_dlightsFPM; + for (i=0 ; ikey == key) + { + Q_memset (dl, 0, sizeof(*dl)); + dl->key = key; + return dl; + } + } + } + +// then look for anything else + dl = cl_dlightsFPM; + for (i=0 ; idie < clFPM.time) + { + Q_memset (dl, 0, sizeof(*dl)); + dl->key = key; + return dl; + } + } + + dl = &cl_dlightsFPM[0]; + Q_memset (dl, 0, sizeof(*dl)); + dl->key = key; + return dl; +} +#endif +/* +=============== +CL_DecayLights + +=============== +*/ +void CL_DecayLights (void) +{ + int i; + dlight_t *dl; + float time; + + time = (float)(cl.time - cl.oldtime); + + dl = cl_dlights; + for (i=0 ; idie < cl.time || !dl->radius) + continue; + + dl->radius -= time*dl->decay; + if (dl->radius < 0) + dl->radius = 0; + } +} + +#ifdef USEFPM +void CL_DecayLightsFPM (void) +{ + int i; + dlight_FPM_t *dl; + fixedpoint_t time; + + time = FPM_FROMFLOAT(clFPM.time - clFPM.oldtime); + + dl = cl_dlightsFPM; + for (i=0 ; idie < clFPM.time || !dl->radius) + continue; + + dl->radius -= FPM_MUL(time, dl->decay); + if (dl->radius < 0) + dl->radius = 0; + } +} +#endif +/* +=============== +CL_LerpPoint + +Determines the fraction between the last two messages that the objects +should be put at. +=============== +*/ +float CL_LerpPoint (void) +{ + float f, frac; + + f = (float)(cl.mtime[0] - cl.mtime[1]); + + if (!f || cl_nolerp.value || cls.timedemo || sv.active) + { + cl.time = cl.mtime[0]; + return 1; + } + + if (f > 0.1) + { // dropped packet, or start of demo + cl.mtime[1] = cl.mtime[0] - 0.1; + f = (float)0.1; + } + frac = (float)((cl.time - cl.mtime[1]) / f); +//Con_Printf ("frac: %f\n",frac); + if (frac < 0) + { + if (frac < -0.01) + { +SetPal(1); + cl.time = cl.mtime[1]; +// Con_Printf ("low frac\n"); + } + frac = 0; + } + else if (frac > 1) + { + if (frac > 1.01) + { +SetPal(2); + cl.time = cl.mtime[0]; +// Con_Printf ("high frac\n"); + } + frac = 1; + } + else + SetPal(0); + + return frac; +} + +#ifdef USEFPM +fixedpoint_t CL_LerpPointFPM (void) +{ + fixedpoint_t f, frac; + + f = FPM_FROMFLOAT(clFPM.mtime[0] - clFPM.mtime[1]); + + if (!f || cl_nolerp.value || cls.timedemo || sv.active) + { + clFPM.time = clFPM.mtime[0]; + return 1; + } + + if (f > FPM_FROMFLOAT(0.1)) + { // dropped packet, or start of demo + clFPM.mtime[1] = clFPM.mtime[0] - 0.1; + f = FPM_FROMFLOAT(0.1); + } + frac = FPM_DIV(FPM_FROMFLOAT(clFPM.time - clFPM.mtime[1]), f); +//Con_Printf ("frac: %f\n",frac); + if (frac < 0) + { + if (frac < FPM_FROMFLOAT(-0.01)) + { + SetPal(1); + clFPM.time = clFPM.mtime[1]; +// Con_Printf ("low frac\n"); + } + frac = 0; + } + else if (frac > FPM_FROMLONG(1)) + { + if (frac > FPM_FROMFLOAT(1.01)) + { + SetPal(2); + clFPM.time = clFPM.mtime[0]; +// Con_Printf ("high frac\n"); + } + frac = FPM_FROMLONG(1); + } + else + SetPal(0); + + return frac; +} +#endif +/* +=============== +CL_RelinkEntities +=============== +*/ +void CL_RelinkEntities (void) +{ + entity_t *ent; + int i, j; + float frac, f, d; + vec3_t delta; + float bobjrotate; + vec3_t oldorg; + dlight_t *dl; + +// determine partial update time + frac = CL_LerpPoint (); + + cl_numvisedicts = 0; + +// +// interpolate player info +// + for (i=0 ; i<3 ; i++) + cl.velocity[i] = cl.mvelocity[1][i] + + frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]); + + if (cls.demoplayback) + { + // interpolate the angles + for (j=0 ; j<3 ; j++) + { + d = cl.mviewangles[0][j] - cl.mviewangles[1][j]; + if (d > 180) + d -= 360; + else if (d < -180) + d += 360; + cl.viewangles[j] = cl.mviewangles[1][j] + frac*d; + } + } + + bobjrotate = anglemod((float)(100*cl.time)); + +// start on the entity after the world + for (i=1,ent=cl_entities+1 ; imodel) + { // empty slot + if (ent->forcelink) + R_RemoveEfrags (ent); // just became empty + continue; + } + +// if the object wasn't included in the last packet, remove it + if (ent->msgtime != cl.mtime[0]) + { + ent->model = NULL; + continue; + } + + VectorCopy (ent->origin, oldorg); + + if (ent->forcelink) + { // the entity was not updated in the last message + // so move to the final spot + VectorCopy (ent->msg_origins[0], ent->origin); + VectorCopy (ent->msg_angles[0], ent->angles); + } + else + { // if the delta is large, assume a teleport and don't lerp + f = frac; + for (j=0 ; j<3 ; j++) + { + delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j]; + if (delta[j] > 100 || delta[j] < -100) + f = 1; // assume a teleportation, not a motion + } + + // interpolate the origin and angles + for (j=0 ; j<3 ; j++) + { + ent->origin[j] = ent->msg_origins[1][j] + f*delta[j]; + + d = ent->msg_angles[0][j] - ent->msg_angles[1][j]; + if (d > 180) + d -= 360; + else if (d < -180) + d += 360; + ent->angles[j] = ent->msg_angles[1][j] + f*d; + } + } + +// rotate binary objects locally + if (ent->model->flags & EF_ROTATE) { + ent->angles[1] = bobjrotate; + ent->origin[2] += (( sin(bobjrotate/90*M_PI) * 5) + 5 ); + } + + if (ent->effects & EF_BRIGHTFIELD) + R_EntityParticles (ent); +#ifdef QUAKE2 + if (ent->effects & EF_DARKFIELD) + R_DarkFieldParticles (ent); +#endif + if (ent->effects & EF_MUZZLEFLASH) + { + vec3_t fv, rv, uv; + + dl = CL_AllocDlight (i); + VectorCopy (ent->origin, dl->origin); + dl->origin[2] += 16; + AngleVectors (ent->angles, fv, rv, uv); + + VectorMA (dl->origin, 18, fv, dl->origin); + dl->radius = (float)(200 + (rand()&31)); + dl->minlight = 32; + dl->die = (float)(cl.time + 0.1); + } + if (ent->effects & EF_BRIGHTLIGHT) + { + dl = CL_AllocDlight (i); + VectorCopy (ent->origin, dl->origin); + dl->origin[2] += 16; + dl->radius = (float)(400 + (rand()&31)); + dl->die = (float)(cl.time + 0.001); + } + if (ent->effects & EF_DIMLIGHT) + { + dl = CL_AllocDlight (i); + VectorCopy (ent->origin, dl->origin); + dl->radius = (float)(200 + (rand()&31)); + dl->die = (float)(cl.time + 0.001); + } +#ifdef QUAKE2 + if (ent->effects & EF_DARKLIGHT) + { + dl = CL_AllocDlight (i); + VectorCopy (ent->origin, dl->origin); + dl->radius = 200.0 + (rand()&31); + dl->die = cl.time + 0.001; + dl->dark = true; + } + if (ent->effects & EF_LIGHT) + { + dl = CL_AllocDlight (i); + VectorCopy (ent->origin, dl->origin); + dl->radius = 200; + dl->die = cl.time + 0.001; + } +#endif + + if (ent->model->flags & EF_GIB) + R_RocketTrail (oldorg, ent->origin, 2); + else if (ent->model->flags & EF_ZOMGIB) + R_RocketTrail (oldorg, ent->origin, 4); + else if (ent->model->flags & EF_TRACER) + R_RocketTrail (oldorg, ent->origin, 3); + else if (ent->model->flags & EF_TRACER2) + R_RocketTrail (oldorg, ent->origin, 5); + else if (ent->model->flags & EF_ROCKET) + { + R_RocketTrail (oldorg, ent->origin, 0); + dl = CL_AllocDlight (i); + VectorCopy (ent->origin, dl->origin); + dl->radius = 200; + dl->die = (float)(cl.time + 0.01); + } + else if (ent->model->flags & EF_GRENADE) + R_RocketTrail (oldorg, ent->origin, 1); + else if (ent->model->flags & EF_TRACER3) + R_RocketTrail (oldorg, ent->origin, 6); + + ent->forcelink = false; + + if (i == cl.viewentity && !chase_active.value) + continue; + +#ifdef QUAKE2 + if ( ent->effects & EF_NODRAW ) + continue; +#endif + if (cl_numvisedicts < MAX_VISEDICTS) + { + cl_visedicts[cl_numvisedicts] = ent; + cl_numvisedicts++; + } + } +} + +#ifdef USEFPM +void CL_RelinkEntitiesFPM (void) +{ + entity_FPM_t *ent; + int i, j; + fixedpoint_t frac, f, d; + vec3_FPM_t delta; + fixedpoint_t bobjrotate; + vec3_FPM_t oldorg; + dlight_FPM_t *dl; + +// determine partial update time + frac = CL_LerpPointFPM (); + + cl_numvisedicts = 0; + +// +// interpolate player info +// + for (i=0 ; i<3 ; i++) + clFPM.velocity[i] = FPM_ADD(clFPM.mvelocity[1][i], + FPM_MUL(frac, FPM_SUB(clFPM.mvelocity[0][i], clFPM.mvelocity[1][i]))); + + if (cls.demoplayback) + { + // interpolate the angles + for (j=0 ; j<3 ; j++) + { + d = FPM_SUB(clFPM.mviewangles[0][j], clFPM.mviewangles[1][j]); + if (d > FPM_FROMLONGC(180)) + d = FPM_SUB(d, FPM_FROMLONGC(360)); + else if (d < FPM_FROMLONGC(-180)) + d = FPM_ADD(d, FPM_FROMLONGC(360)); + clFPM.viewangles[j] = FPM_ADD(clFPM.mviewangles[1][j], FPM_MUL(frac,d)); + } + } + + bobjrotate = anglemodFPM(FPM_MUL(FPM_FROMLONGC(100),FPM_FROMFLOAT(clFPM.time))); + +// start on the entity after the world + for (i=1,ent=cl_entitiesFPM+1 ; imodel) + { // empty slot + if (ent->forcelink) + R_RemoveEfragsFPM (ent); // just became empty + continue; + } + +// if the object wasn't included in the last packet, remove it + if (ent->msgtime != clFPM.mtime[0]) + { + ent->model = NULL; + continue; + } + + VectorCopy (ent->origin, oldorg); + + if (ent->forcelink) + { // the entity was not updated in the last message + // so move to the final spot + VectorCopy (ent->msg_origins[0], ent->origin); + VectorCopy (ent->msg_angles[0], ent->angles); + } + else + { // if the delta is large, assume a teleport and don't lerp + f = frac; + for (j=0 ; j<3 ; j++) + { + delta[j] = FPM_SUB(ent->msg_origins[0][j], ent->msg_origins[1][j]); + if (delta[j] > FPM_FROMLONGC(100) || delta[j] < FPM_FROMLONGC(-100)) + f = FPM_FROMLONG(1); // assume a teleportation, not a motion + } + + // interpolate the origin and angles + for (j=0 ; j<3 ; j++) + { + ent->origin[j] = FPM_ADD(ent->msg_origins[1][j], FPM_MUL(f,delta[j])); + + d = FPM_SUB(ent->msg_angles[0][j], ent->msg_angles[1][j]); + if (d > FPM_FROMLONGC(180)) + d = FPM_SUB(d, FPM_FROMLONGC(360)); + else if (d < FPM_FROMLONGC(-180)) + d = FPM_ADD(d, FPM_FROMLONGC(360)); + ent->angles[j] = FPM_ADD(ent->msg_angles[1][j], FPM_MUL(f,d)); + } + + } + +// rotate binary objects locally + if (ent->model->flags & EF_ROTATE) + ent->angles[1] = bobjrotate; + + if (ent->effects & EF_BRIGHTFIELD) + R_EntityParticlesFPM (ent); +#ifdef QUAKE2 + if (ent->effects & EF_DARKFIELD) + R_DarkFieldParticlesFPM (ent); +#endif + if (ent->effects & EF_MUZZLEFLASH) + { + vec3_FPM_t fv, rv, uv; + + dl = CL_AllocDlightFPM (i); + VectorCopy (ent->origin, dl->origin); + dl->origin[2] = FPM_ADD(dl->origin[2], FPM_FROMLONGC(16)); + AngleVectorsFPM (ent->angles, fv, rv, uv); + + VectorMAFPM (dl->origin, FPM_FROMLONG(18), fv, dl->origin); + dl->radius = FPM_FROMLONG(200 + (rand()&31)); + dl->minlight = 32; + dl->die = FPM_ADD(FPM_FROMFLOAT(clFPM.time), FPM_FROMFLOATC(0.1)); + } + if (ent->effects & EF_BRIGHTLIGHT) + { + dl = CL_AllocDlightFPM (i); + VectorCopy (ent->origin, dl->origin); + dl->origin[2] = FPM_ADD(dl->origin[2], FPM_FROMLONGC(16)); + dl->radius = FPM_FROMLONG(400 + (rand()&31)); + dl->die = FPM_ADD(FPM_FROMFLOAT(clFPM.time), FPM_FROMFLOATC(0.001)); + } + if (ent->effects & EF_DIMLIGHT) + { + dl = CL_AllocDlightFPM (i); + VectorCopy (ent->origin, dl->origin); + dl->radius = FPM_FROMLONG(200 + (rand()&31)); + dl->die = FPM_ADD(FPM_FROMFLOAT(clFPM.time), FPM_FROMFLOATC(0.001)); + } +#ifdef QUAKE2 + if (ent->effects & EF_DARKLIGHT) + { + dl = CL_AllocDlightFPM (i); + VectorCopy (ent->origin, dl->origin); + dl->radius = FPM_FROMLONG(200.0 + (rand()&31)); + dl->die = FPM_ADD(FPM_FROMFLOAT(clFPM.time), FPM_FROMFLOATC(0.001)); + dl->dark = true; + } + if (ent->effects & EF_LIGHT) + { + dl = CL_AllocDlightFPM (i); + VectorCopy (ent->origin, dl->origin); + dl->radius = FPM_FROMLONG(200); + dl->die = FPM_ADD(FPM_FROMFLOAT(clFPM.time), FPM_FROMFLOATC(0.001)); + } +#endif + + if (ent->model->flags & EF_GIB) + R_RocketTrailFPM (oldorg, ent->origin, 2); + else if (ent->model->flags & EF_ZOMGIB) + R_RocketTrailFPM (oldorg, ent->origin, 4); + else if (ent->model->flags & EF_TRACER) + R_RocketTrailFPM (oldorg, ent->origin, 3); + else if (ent->model->flags & EF_TRACER2) + R_RocketTrailFPM (oldorg, ent->origin, 5); + else if (ent->model->flags & EF_ROCKET) + { + R_RocketTrailFPM (oldorg, ent->origin, 0); + dl = CL_AllocDlightFPM (i); + VectorCopy (ent->origin, dl->origin); + dl->radius = FPM_FROMLONGC(200); + dl->die = FPM_ADD(FPM_FROMFLOAT(clFPM.time), FPM_FROMFLOATC(0.01)); + } + else if (ent->model->flags & EF_GRENADE) + R_RocketTrailFPM (oldorg, ent->origin, 1); + else if (ent->model->flags & EF_TRACER3) + R_RocketTrailFPM (oldorg, ent->origin, 6); + + ent->forcelink = false; + + if (i == clFPM.viewentity && !chase_active.value) + continue; + +#ifdef QUAKE2 + if ( ent->effects & EF_NODRAW ) + continue; +#endif + if (cl_numvisedicts < MAX_VISEDICTS) + { + cl_visedictsFPM[cl_numvisedicts] = ent; + cl_numvisedicts++; + } + } +} +#endif +/* +=============== +CL_ReadFromServer + +Read all incoming data from the server +=============== +*/ +int CL_ReadFromServer (void) +{ + int ret; + + cl.oldtime = cl.time; + cl.time += host_frametime; + + do + { + + + ret = CL_GetMessage (); + if (ret == -1){ + Host_Error ("CL_ReadFromServer: lost server connection"); + } + if (!ret) + break; + + + cl.last_received_message = (float)realtime; + CL_ParseServerMessage (); + + + } while (ret && cls.state == ca_connected); + + + if (cl_shownet.value) + Con_Printf ("\n"); + + CL_RelinkEntities (); + CL_UpdateTEnts (); + +// +// bring the links up to date +// + + return 0; +} + +#ifdef USEFPM +int CL_ReadFromServerFPM (void) +{ + int ret; + + clFPM.oldtime = clFPM.time; + clFPM.time += host_frametime; + + do + { + ret = CL_GetMessageFPM (); + if (ret == -1) + Host_Error ("CL_ReadFromServer: lost server connection"); + if (!ret) + break; + + clFPM.last_received_message = (float)realtime; + CL_ParseServerMessageFPM (); + } while (ret && cls.state == ca_connected); + + if (cl_shownet.value) + Con_Printf ("\n"); + + CL_RelinkEntitiesFPM (); + CL_UpdateTEntsFPM (); + +// +// bring the links up to date +// + return 0; +} +#endif +/* +================= +CL_SendCmd +================= +*/ +void CL_SendCmd (void) +{ + usercmd_t cmd; + + if (cls.state != ca_connected) + return; + + GpError("CL_SendCmd",2); + + if (cls.signon == SIGNONS) + { + GpError("CL_SendCmd send signons",0); + // get basic movement from keyboard + CL_BaseMove (&cmd); + + // allow mice or other external controllers to add to the move + IN_Move (&cmd); + + // send the unreliable message + CL_SendMove (&cmd); + + } + + if (cls.demoplayback) + { + SZ_Clear (&cls.message); + return; + } + +// send the reliable message + if (!cls.message.cursize){ + GpError("CL_SendCmd no mes",0); + return; // no message at all + } + + if (!NET_CanSendMessage (cls.netcon)) + { + GpError("CL_SendCmd cant send",0); + Con_DPrintf ("CL_WriteToServer: can't send\n"); + return; + } + + if (NET_SendMessage (cls.netcon, &cls.message) == -1){ + GpError("CL_SendCmd lost con",2); + Host_Error ("CL_WriteToServer: lost server connection"); + } + + SZ_Clear (&cls.message); + GpError("CL_SendCmd done",1); +} + +#ifdef USEFPM +void CL_SendCmdFPM (void) +{ + usercmd_FPM_t cmd; + + if (cls.state != ca_connected) + return; + + if (cls.signon == SIGNONS) + { + // get basic movement from keyboard + CL_BaseMoveFPM (&cmd); + + // allow mice or other external controllers to add to the move +// IN_MoveFPM (&cmd); + + // send the unreliable message + CL_SendMoveFPM (&cmd); + + } + + if (cls.demoplayback) + { + SZ_Clear (&cls.message); + return; + } + +// send the reliable message + if (!cls.message.cursize) + return; // no message at all + + if (!NET_CanSendMessage (cls.netcon)) + { + Con_DPrintf ("CL_WriteToServer: can't send\n"); + return; + } + + if (NET_SendMessage (cls.netcon, &cls.message) == -1) + Host_Error ("CL_WriteToServer: lost server connection"); + + SZ_Clear (&cls.message); +} +#endif +/* +================= +CL_Init +================= +*/ +void CL_Init (void) +{ + SZ_Alloc (&cls.message, 1024); + + CL_InitInput (); + CL_InitTEnts (); + +// +// register our commands +// + Cvar_RegisterVariable (&command); + Cvar_RegisterVariable (&cl_name); + Cvar_RegisterVariable (&cl_color); + Cvar_RegisterVariable (&cl_upspeed); + Cvar_RegisterVariable (&cl_forwardspeed); + Cvar_RegisterVariable (&cl_backspeed); + Cvar_RegisterVariable (&cl_sidespeed); + Cvar_RegisterVariable (&cl_movespeedkey); + Cvar_RegisterVariable (&cl_yawspeed); + Cvar_RegisterVariable (&cl_pitchspeed); + Cvar_RegisterVariable (&cl_anglespeedkey); + Cvar_RegisterVariable (&cl_showfps);// 2001-11-31 FPS display by QuakeForge/Muff + Cvar_RegisterVariable (&cl_shownet); + Cvar_RegisterVariable (&cl_nolerp); + Cvar_RegisterVariable (&lookspring); + Cvar_RegisterVariable (&lookstrafe); + Cvar_RegisterVariable (&sensitivity); + + Cvar_RegisterVariable (&m_pitch); + Cvar_RegisterVariable (&m_yaw); + Cvar_RegisterVariable (&m_forward); + Cvar_RegisterVariable (&m_side); + + Cvar_RegisterVariable (&cl_config); + +// Cvar_RegisterVariable (&cl_autofire); + + Cmd_AddCommand ("entities", CL_PrintEntities_f); + Cmd_AddCommand ("disconnect", CL_Disconnect_f); + Cmd_AddCommand ("record", CL_Record_f); + Cmd_AddCommand ("stop", CL_Stop_f); + //Cmd_AddCommand ("gpplaydemo", CL_PlayDemo_f); + // Cmd_AddCommand ("playdemo", CL_PlayDemo_silentfail); + Cmd_AddCommand ("playdemo", CL_PlayDemo_f); + Cmd_AddCommand ("timedemo", CL_TimeDemo_f); +} + diff --git a/project/jni/application/quake/source/cl_parse.c b/project/jni/application/quake/source/cl_parse.c new file mode 100644 index 000000000..be26b1f8f --- /dev/null +++ b/project/jni/application/quake/source/cl_parse.c @@ -0,0 +1,1759 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cl_parse.c -- parse a message received from the server + +#include "quakedef.h" + +//Dan East: +//We need to know the console char width for a modification below +extern int con_linewidth; + +char *svc_strings[] = +{ + "svc_bad", + "svc_nop", + "svc_disconnect", + "svc_updatestat", + "svc_version", // [long] server version + "svc_setview", // [short] entity number + "svc_sound", // + "svc_time", // [float] server time + "svc_print", // [string] null terminated string + "svc_stufftext", // [string] stuffed into client's console buffer + // the string should be \n terminated + "svc_setangle", // [vec3] set the view angle to this absolute value + + "svc_serverinfo", // [long] version + // [string] signon string + // [string]..[0]model cache [string]...[0]sounds cache + // [string]..[0]item cache + "svc_lightstyle", // [byte] [string] + "svc_updatename", // [byte] [string] + "svc_updatefrags", // [byte] [short] + "svc_clientdata", // + "svc_stopsound", // + "svc_updatecolors", // [byte] [byte] + "svc_particle", // [vec3] + "svc_damage", // [byte] impact [byte] blood [vec3] from + + "svc_spawnstatic", + "OBSOLETE svc_spawnbinary", + "svc_spawnbaseline", + + "svc_temp_entity", // + "svc_setpause", + "svc_signonnum", + "svc_centerprint", + "svc_killedmonster", + "svc_foundsecret", + "svc_spawnstaticsound", + "svc_intermission", + "svc_finale", // [string] music [string] text + "svc_cdtrack", // [byte] track [byte] looptrack + "svc_sellscreen", + "svc_cutscene" +}; + +//============================================================================= + +/* +=============== +CL_EntityNum + +This error checks and tracks the total number of entities +=============== +*/ +entity_t *CL_EntityNum (int num) +{ + if (num >= cl.num_entities) + { + if (num >= MAX_EDICTS) + Host_Error ("CL_EntityNum: %i is an invalid number",num); + while (cl.num_entities<=num) + { + cl_entities[cl.num_entities].colormap = vid.colormap; + cl.num_entities++; + } + } + + return &cl_entities[num]; +} + +#ifdef USEFPM +entity_FPM_t *CL_EntityNumFPM (int num) +{ + if (num >= clFPM.num_entities) + { + if (num >= MAX_EDICTS) + Host_Error ("CL_EntityNum: %i is an invalid number",num); + while (clFPM.num_entities<=num) + { + cl_entitiesFPM[clFPM.num_entities].colormap = vid.colormap; + clFPM.num_entities++; + } + } + + return &cl_entitiesFPM[num]; +} +#endif + +/* +================== +CL_ParseStartSoundPacket +================== +*/ +void CL_ParseStartSoundPacket(void) +{ + vec3_t pos; + int channel, ent; + int sound_num; + int volume; + int field_mask; + float attenuation; + int i; + + field_mask = MSG_ReadByte(); + + if (field_mask & SND_VOLUME) + volume = MSG_ReadByte (); + else + volume = DEFAULT_SOUND_PACKET_VOLUME; + + if (field_mask & SND_ATTENUATION) + attenuation = (float)(MSG_ReadByte () / 64.0); + else + attenuation = DEFAULT_SOUND_PACKET_ATTENUATION; + + channel = MSG_ReadShort (); + sound_num = MSG_ReadByte (); + + ent = channel >> 3; + channel &= 7; + + if (ent > MAX_EDICTS) + Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent); + + for (i=0 ; i<3 ; i++) + pos[i] = MSG_ReadCoord (); + + S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, (float)(volume/255.0), attenuation); +} + + +/* +================== +CL_KeepaliveMessage + +When the client is taking a long time to load stuff, send keepalive messages +so the server doesn't disconnect. +================== +*/ +void CL_KeepaliveMessage (void) +{ + float time; + static float lastmsg; + int ret; + sizebuf_t old; + byte olddata[8192]; + + if (sv.active) + return; // no need if server is local + if (cls.demoplayback) + return; + +// read messages from server, should just be nops + old = net_message; + Q_memcpy (olddata, net_message.data, net_message.cursize); + + do + { + ret = CL_GetMessage (); + switch (ret) + { + default: + Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed"); + case 0: + break; // nothing waiting + case 1: + Host_Error ("CL_KeepaliveMessage: received a message"); + break; + case 2: + if (MSG_ReadByte() != svc_nop) + Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop"); + break; + } + } while (ret); + + net_message = old; + Q_memcpy (net_message.data, olddata, net_message.cursize); + +// check time + time = (float)Sys_FloatTime (); + if (time - lastmsg < 5) + return; + lastmsg = time; + +// write out a nop + Con_Printf ("--> client to server keepalive\n"); + + MSG_WriteByte (&cls.message, clc_nop); + NET_SendMessage (cls.netcon, &cls.message); + SZ_Clear (&cls.message); +} + +/* +================== +CL_ParseServerInfo +================== +*/ +void CL_ParseServerInfo (void) +{ + char *str; + int i; + int nummodels, numsounds; + char model_precache[MAX_MODELS][MAX_QPATH]; + char sound_precache[MAX_SOUNDS][MAX_QPATH]; + char tmp[80]; + + + GpError("CL_ParseServerInfo",1); + + Con_DPrintf ("Serverinfo packet received.\n"); +// +// wipe the client_state_t struct +// + CL_ClearState (); + +// parse protocol version number + i = MSG_ReadLong (); + if (i != PROTOCOL_VERSION) + { + Con_Printf ("Server returned version %i, not %i", i, PROTOCOL_VERSION); + return; + } + +// parse maxclients + cl.maxclients = MSG_ReadByte (); + if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD) + { + Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients); + return; + } + cl.scores = Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores"); + +// parse gametype + cl.gametype = MSG_ReadByte (); + +// parse signon message + str = MSG_ReadString (); + strncpy (cl.levelname, str, sizeof(cl.levelname)-1); + +// seperate the printfs so the server message can have a color + //Dan East: The original code hardcoded a console char width of 38 characters. I've + //modified this to dynamically match the console width. + if (con_linewidth>=sizeof(tmp)) i=sizeof(tmp)-1; + else i=con_linewidth; + tmp[i--]='\0'; + tmp[i--]='\37'; + while (i) tmp[i--]='\36'; + tmp[i]='\35'; + + Con_Printf("\n\n"); + Con_Printf(tmp); + + //Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); + Con_Printf ("%c%s\n", 2, str); + +// +// first we go through and touch all of the precache data that still +// happens to be in the cache, so precaching something else doesn't +// needlessly purge it +// + +// precache models + Q_memset (cl.model_precache, 0, sizeof(cl.model_precache)); + for (nummodels=1 ; ; nummodels++) + { + str = MSG_ReadString (); + if (!str[0]) + break; + if (nummodels==MAX_MODELS) + { + Con_Printf ("Server sent too many model precaches\n"); + return; + } + strcpy (model_precache[nummodels], str); + Mod_TouchModel (str); + } + +// precache sounds + Q_memset (cl.sound_precache, 0, sizeof(cl.sound_precache)); + for (numsounds=1 ; ; numsounds++) + { + str = MSG_ReadString (); + if (!str[0]) + break; + if (numsounds==MAX_SOUNDS) + { + Con_Printf ("Server sent too many sound precaches\n"); + return; + } + strcpy (sound_precache[numsounds], str); + S_TouchSound (str); + } + +// +// now we try to load everything else until a cache allocation fails +// + + for (i=1 ; i MAX_SCOREBOARD) + { + Con_Printf("Bad maxclients (%u) from server\n", clFPM.maxclients); + return; + } + clFPM.scores = Hunk_AllocName (clFPM.maxclients*sizeof(*clFPM.scores), "scores"); + +// parse gametype + clFPM.gametype = MSG_ReadByte (); + +// parse signon message + str = MSG_ReadString (); + strncpy (clFPM.levelname, str, sizeof(clFPM.levelname)-1); + +// seperate the printfs so the server message can have a color + //Dan East: The original code hardcoded a console char width of 38 characters. I've + //modified this to dynamically match the console width. + Con_Printf("\n\n\35"); + for (i=0; imsgtime != cl.mtime[1]) + forcelink = true; // no previous frame to lerp from + else + forcelink = false; + + ent->msgtime = cl.mtime[0]; + + if (bits & U_MODEL) + { + modnum = MSG_ReadByte (); + if (modnum >= MAX_MODELS) + Host_Error ("CL_ParseModel: bad modnum"); + } + else + modnum = ent->baseline.modelindex; + + model = cl.model_precache[modnum]; + if (model != ent->model) + { + ent->model = model; + // automatic animation (torches, etc) can be either all together + // or randomized + if (model) + { + if (model->synctype == ST_RAND) + ent->syncbase = (float)(rand()&0x7fff) / 0x7fff; + else + ent->syncbase = 0.0; + } + else + forcelink = true; // hack to make null model players work +#ifdef GLQUAKE + if (num > 0 && num <= cl.maxclients) + R_TranslatePlayerSkin (num - 1); +#endif + } + + + if (bits & U_FRAME) + ent->frame = MSG_ReadByte (); + else + ent->frame = ent->baseline.frame; + + if (bits & U_COLORMAP) + i = MSG_ReadByte(); + else + i = ent->baseline.colormap; + if (!i) + ent->colormap = vid.colormap; + else + { + if (i > cl.maxclients) + Sys_Error ("i >= cl.maxclients"); + ent->colormap = cl.scores[i-1].translations; + } + +#ifdef GLQUAKE + if (bits & U_SKIN) + skin = MSG_ReadByte(); + else + skin = ent->baseline.skin; + if (skin != ent->skinnum) { + ent->skinnum = skin; + if (num > 0 && num <= cl.maxclients) + R_TranslatePlayerSkin (num - 1); + } + +#else + + if (bits & U_SKIN) + ent->skinnum = MSG_ReadByte(); + else + ent->skinnum = ent->baseline.skin; +#endif + + if (bits & U_EFFECTS) + ent->effects = MSG_ReadByte(); + else + ent->effects = ent->baseline.effects; + +// shift the known values for interpolation + VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); + VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); + + if (bits & U_ORIGIN1) + ent->msg_origins[0][0] = MSG_ReadCoord (); + else + ent->msg_origins[0][0] = ent->baseline.origin[0]; + if (bits & U_ANGLE1) + ent->msg_angles[0][0] = MSG_ReadAngle(); + else + ent->msg_angles[0][0] = ent->baseline.angles[0]; + + if (bits & U_ORIGIN2) + ent->msg_origins[0][1] = MSG_ReadCoord (); + else + ent->msg_origins[0][1] = ent->baseline.origin[1]; + if (bits & U_ANGLE2) + ent->msg_angles[0][1] = MSG_ReadAngle(); + else + ent->msg_angles[0][1] = ent->baseline.angles[1]; + + if (bits & U_ORIGIN3) + ent->msg_origins[0][2] = MSG_ReadCoord (); + else + ent->msg_origins[0][2] = ent->baseline.origin[2]; + if (bits & U_ANGLE3) + ent->msg_angles[0][2] = MSG_ReadAngle(); + else + ent->msg_angles[0][2] = ent->baseline.angles[2]; + + if ( bits & U_NOLERP ) + ent->forcelink = true; + + if ( forcelink ) + { // didn't have an update last message + VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); + VectorCopy (ent->msg_origins[0], ent->origin); + VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); + VectorCopy (ent->msg_angles[0], ent->angles); + ent->forcelink = true; + } + GpError("CL_ParseUpdate done",1); + +} + +#ifdef USEFPM +void CL_ParseUpdateFPM (int bits) +{ + int i; + model_FPM_t *model; + int modnum; + qboolean forcelink; + entity_FPM_t *ent; + int num; +// int skin; //Dan: unused var + + if (cls.signon == SIGNONS - 1) + { // first update is the final signon stage + cls.signon = SIGNONS; + CL_SignonReply (); + } + + if (bits & U_MOREBITS) + { + i = MSG_ReadByte (); + bits |= (i<<8); + } + + if (bits & U_LONGENTITY) + num = MSG_ReadShort (); + else + num = MSG_ReadByte (); + + ent = CL_EntityNumFPM (num); + + for (i=0 ; i<16 ; i++) + if (bits&(1<msgtime != clFPM.mtime[1]) + forcelink = true; // no previous frame to lerp from + else + forcelink = false; + + ent->msgtime = clFPM.mtime[0]; + + if (bits & U_MODEL) + { + modnum = MSG_ReadByte (); + if (modnum >= MAX_MODELS) + Host_Error ("CL_ParseModel: bad modnum"); + } + else + modnum = ent->baseline.modelindex; + + model = clFPM.model_precache[modnum]; + if (model != ent->model) + { + ent->model = model; + // automatic animation (torches, etc) can be either all together + // or randomized + if (model) + { + if (model->synctype == ST_RAND) + ent->syncbase = (float)(rand()&0x7fff) / 0x7fff; + else + ent->syncbase = 0.0; + } + else + forcelink = true; // hack to make null model players work +#ifdef GLQUAKE + if (num > 0 && num <= cl.maxclients) + R_TranslatePlayerSkin (num - 1); +#endif + } + + if (bits & U_FRAME) + ent->frame = MSG_ReadByte (); + else + ent->frame = ent->baseline.frame; + + if (bits & U_COLORMAP) + i = MSG_ReadByte(); + else + i = ent->baseline.colormap; + if (!i) + ent->colormap = vid.colormap; + else + { + if (i > clFPM.maxclients) + Sys_Error ("i >= cl.maxclients"); + ent->colormap = clFPM.scores[i-1].translations; + } + +#ifdef GLQUAKE + if (bits & U_SKIN) + skin = MSG_ReadByte(); + else + skin = ent->baseline.skin; + if (skin != ent->skinnum) { + ent->skinnum = skin; + if (num > 0 && num <= clFPM.maxclients) + R_TranslatePlayerSkin (num - 1); + } + +#else + + if (bits & U_SKIN) + ent->skinnum = MSG_ReadByte(); + else + ent->skinnum = ent->baseline.skin; +#endif + + if (bits & U_EFFECTS) + ent->effects = MSG_ReadByte(); + else + ent->effects = ent->baseline.effects; + +// shift the known values for interpolation + VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); + VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); + + if (bits & U_ORIGIN1) + ent->msg_origins[0][0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + else + ent->msg_origins[0][0] = ent->baseline.origin[0]; + if (bits & U_ANGLE1) + ent->msg_angles[0][0] = FPM_FROMFLOAT(MSG_ReadAngle()); + else + ent->msg_angles[0][0] = ent->baseline.angles[0]; + + if (bits & U_ORIGIN2) + ent->msg_origins[0][1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + else + ent->msg_origins[0][1] = ent->baseline.origin[1]; + if (bits & U_ANGLE2) + ent->msg_angles[0][1] = FPM_FROMFLOAT(MSG_ReadAngle()); + else + ent->msg_angles[0][1] = ent->baseline.angles[1]; + + if (bits & U_ORIGIN3) + ent->msg_origins[0][2] = FPM_FROMFLOAT(MSG_ReadCoord ()); + else + ent->msg_origins[0][2] = ent->baseline.origin[2]; + if (bits & U_ANGLE3) + ent->msg_angles[0][2] = FPM_FROMFLOAT(MSG_ReadAngle()); + else + ent->msg_angles[0][2] = ent->baseline.angles[2]; + + if ( bits & U_NOLERP ) + ent->forcelink = true; + + if ( forcelink ) + { // didn't have an update last message + VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); + VectorCopy (ent->msg_origins[0], ent->origin); + VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); + VectorCopy (ent->msg_angles[0], ent->angles); + ent->forcelink = true; + } +} +#endif +/* +================== +CL_ParseBaseline +================== +*/ +void CL_ParseBaseline (entity_t *ent) +{ + int i; + + + ent->baseline.modelindex = MSG_ReadByte (); + ent->baseline.frame = MSG_ReadByte (); + ent->baseline.colormap = MSG_ReadByte(); + ent->baseline.skin = MSG_ReadByte(); + for (i=0 ; i<3 ; i++) + { + ent->baseline.origin[i] = MSG_ReadCoord (); + ent->baseline.angles[i] = MSG_ReadAngle (); + } +} + +#ifdef USEFPM +void CL_ParseBaselineFPM (entity_FPM_t *ent) +{ + int i; + + ent->baseline.modelindex = MSG_ReadByte (); + ent->baseline.frame = MSG_ReadByte (); + ent->baseline.colormap = MSG_ReadByte(); + ent->baseline.skin = MSG_ReadByte(); + for (i=0 ; i<3 ; i++) + { + ent->baseline.origin[i] = FPM_FROMFLOAT(MSG_ReadCoord ()); + ent->baseline.angles[i] = FPM_FROMFLOAT(MSG_ReadAngle ()); + } +} +#endif +/* +================== +CL_ParseClientdata + +Server information pertaining to this client only +================== +*/ +void CL_ParseClientdata (int bits) +{ + int i, j; + + GpError("CL_ParseClientData",2); + + if (bits & SU_VIEWHEIGHT) + cl.viewheight = (float)MSG_ReadChar (); + else + cl.viewheight = DEFAULT_VIEWHEIGHT; + + if (bits & SU_IDEALPITCH) + cl.idealpitch = (float)MSG_ReadChar (); + else + cl.idealpitch = 0; + + VectorCopy (cl.mvelocity[0], cl.mvelocity[1]); + for (i=0 ; i<3 ; i++) + { + if (bits & (SU_PUNCH1< cl.maxclients) + Sys_Error ("CL_NewTranslation: slot > cl.maxclients"); + dest = cl.scores[slot].translations; + source = vid.colormap; + Q_memcpy (dest, vid.colormap, sizeof(cl.scores[slot].translations)); + top = cl.scores[slot].colors & 0xf0; + bottom = (cl.scores[slot].colors &15)<<4; +#ifdef GLQUAKE + R_TranslatePlayerSkin (slot); +#endif + + for (i=0 ; i clFPM.maxclients) + Sys_Error ("CL_NewTranslation: slot > cl.maxclients"); + dest = clFPM.scores[slot].translations; + source = vid.colormap; + Q_memcpy (dest, vid.colormap, sizeof(clFPM.scores[slot].translations)); + top = clFPM.scores[slot].colors & 0xf0; + bottom = (clFPM.scores[slot].colors &15)<<4; +#ifdef GLQUAKE + R_TranslatePlayerSkin (slot); +#endif + + for (i=0 ; i= MAX_STATIC_ENTITIES){ + Host_Error ("Too many static entities"); + } + ent = &cl_static_entities[i]; + cl.num_statics++; + CL_ParseBaseline (ent); + +// copy it to the current state + ent->model = cl.model_precache[ent->baseline.modelindex]; + ent->frame = ent->baseline.frame; + ent->colormap = vid.colormap; + ent->skinnum = ent->baseline.skin; + ent->effects = ent->baseline.effects; + + VectorCopy (ent->baseline.origin, ent->origin); + VectorCopy (ent->baseline.angles, ent->angles); + R_AddEfrags (ent); +} + +#ifdef USEFPM +void CL_ParseStaticFPM (void) +{ + entity_FPM_t *ent; + int i; + + i = clFPM.num_statics; + if (i >= MAX_STATIC_ENTITIES) + Host_Error ("Too many static entities"); + ent = &cl_static_entitiesFPM[i]; + clFPM.num_statics++; + CL_ParseBaselineFPM (ent); + +// copy it to the current state + ent->model = clFPM.model_precache[ent->baseline.modelindex]; + ent->frame = ent->baseline.frame; + ent->colormap = vid.colormap; + ent->skinnum = ent->baseline.skin; + ent->effects = ent->baseline.effects; + + VectorCopy (ent->baseline.origin, ent->origin); + VectorCopy (ent->baseline.angles, ent->angles); + R_AddEfragsFPM (ent); +} +#endif +/* +=================== +CL_ParseStaticSound +=================== +*/ +void CL_ParseStaticSound (void) +{ + vec3_t org; + int sound_num, vol, atten; + int i; + + for (i=0 ; i<3 ; i++) + org[i] = MSG_ReadCoord (); + sound_num = MSG_ReadByte (); + vol = MSG_ReadByte (); + atten = MSG_ReadByte (); + + S_StaticSound (cl.sound_precache[sound_num], org, (float)vol, (float)atten); +} + +#ifdef USEFPM +void CL_ParseStaticSoundFPM (void) +{ + vec3_t org; + int sound_num, vol, atten; + int i; + + for (i=0 ; i<3 ; i++) + org[i] = MSG_ReadCoord (); + sound_num = MSG_ReadByte (); + vol = MSG_ReadByte (); + atten = MSG_ReadByte (); + + S_StaticSound (clFPM.sound_precache[sound_num], org, (float)vol, (float)atten); +} +#endif + +#define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x); + +/* +===================== +CL_ParseServerMessage +===================== +*/ +void CL_ParseServerMessage (void) +{ + int cmd; + int i; + +// if(sv.active) +// GpError("CL_ParseServerMessage start",5); +// +// if recording demos, copy the message out +// + if (cl_shownet.value == 1) + Con_Printf ("%i ",net_message.cursize); + else if (cl_shownet.value == 2) + Con_Printf ("------------------\n"); + + cl.onground = false; // unless the server says otherwise +// +// parse the message +// + MSG_BeginReading (); + + while (1) + { + + if (msg_badread){ + GpError("PSM : Bad server message",666); + Host_Error ("CL_ParseServerMessage: Bad server message"); + } + + cmd = MSG_ReadByte (); + + if (cmd == -1) + { + SHOWNET("END OF MESSAGE"); + return; // end of message + } + +// sprintf(gpstr,"PSM:Mes=[%i] %s",cmd&127, svc_strings[cmd&127]); +// GpError(gpstr,1); + + // if the high bit of the command byte is set, it is a fast update + if (cmd & 128) + { +// GpError("PSM : Fast update",1); + SHOWNET("fast update"); + CL_ParseUpdate (cmd&127); + continue; + } + + SHOWNET(svc_strings[cmd]); + + // other commands + switch (cmd) + { + default: + Host_Error ("CL_ParseServerMessage: Illegible server message\n"); + break; + + case svc_nop: +// Con_Printf ("svc_nop\n"); + break; + + case svc_time: + cl.mtime[1] = cl.mtime[0]; + cl.mtime[0] = MSG_ReadFloat (); + break; + + case svc_clientdata: + i = MSG_ReadShort (); + CL_ParseClientdata (i); + break; + + case svc_version: + i = MSG_ReadLong (); + if (i != PROTOCOL_VERSION) + Host_Error ("CL_ParseServerMessage: Server is protocol %i instead of %i\n", i, PROTOCOL_VERSION); + break; + + case svc_disconnect: + Host_EndGame ("Server disconnected\n"); + + case svc_print: + Con_Printf ("%s", MSG_ReadString ()); + break; + + case svc_centerprint: + SCR_CenterPrint (MSG_ReadString ()); + break; + + case svc_stufftext: + Cbuf_AddText (MSG_ReadString ()); + break; + + case svc_damage: + V_ParseDamage (); + break; + + case svc_serverinfo: + CL_ParseServerInfo (); + vid.recalc_refdef = true; // leave intermission full screen + break; + + case svc_setangle: + for (i=0 ; i<3 ; i++) + cl.viewangles[i] = MSG_ReadAngle (); + break; + + case svc_setview: + cl.viewentity = MSG_ReadShort (); + break; + + case svc_lightstyle: + i = MSG_ReadByte (); + if (i >= MAX_LIGHTSTYLES) + Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); + Q_strcpy (cl_lightstyle[i].map, MSG_ReadString()); + cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map); + break; + + case svc_sound: + CL_ParseStartSoundPacket(); + break; + + case svc_stopsound: + i = MSG_ReadShort(); + S_StopSound(i>>3, i&7); + break; + + case svc_updatename: + Sbar_Changed (); + i = MSG_ReadByte (); + if (i >= cl.maxclients) + Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD"); + strcpy (cl.scores[i].name, MSG_ReadString ()); + break; + + case svc_updatefrags: + Sbar_Changed (); + i = MSG_ReadByte (); + if (i >= cl.maxclients) + Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD"); + cl.scores[i].frags = MSG_ReadShort (); + break; + + case svc_updatecolors: + Sbar_Changed (); + i = MSG_ReadByte (); + if (i >= cl.maxclients) + Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD"); + cl.scores[i].colors = MSG_ReadByte (); + CL_NewTranslation (i); + break; + + case svc_particle: + R_ParseParticleEffect (); + break; + + case svc_spawnbaseline: + i = MSG_ReadShort (); + // must use CL_EntityNum() to force cl.num_entities up + + //sprintf(gpstr,"CL_ParseBaseLine %i", i); + //GpError(gpstr,1); + CL_ParseBaseline (CL_EntityNum(i)); + break; + case svc_spawnstatic: + CL_ParseStatic (); + break; + case svc_temp_entity: + CL_ParseTEnt (); + break; + + case svc_setpause: + { + cl.paused = MSG_ReadByte (); + + if (cl.paused) + { + CDAudio_Pause (); +#ifdef _WIN32 + VID_HandlePause (true); +#endif + } + else + { + CDAudio_Resume (); +#ifdef _WIN32 + VID_HandlePause (false); +#endif + } + } + break; + + case svc_signonnum: + i = MSG_ReadByte (); + if (i <= cls.signon) + Host_Error ("Received signon %i when at %i", i, cls.signon); + cls.signon = i; + CL_SignonReply (); + break; + + case svc_killedmonster: + cl.stats[STAT_MONSTERS]++; + break; + + case svc_foundsecret: + cl.stats[STAT_SECRETS]++; + break; + + case svc_updatestat: + i = MSG_ReadByte (); + if (i < 0 || i >= MAX_CL_STATS) + Sys_Error ("svc_updatestat: %i is invalid", i); + cl.stats[i] = MSG_ReadLong ();; + break; + + case svc_spawnstaticsound: + CL_ParseStaticSound (); + break; + + case svc_cdtrack: + cl.cdtrack = MSG_ReadByte (); + cl.looptrack = MSG_ReadByte (); + if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) + CDAudio_Play ((byte)cls.forcetrack, true); + else + CDAudio_Play ((byte)cl.cdtrack, true); + break; + + case svc_intermission: + cl.intermission = 1; + cl.completed_time = (int)cl.time; + vid.recalc_refdef = true; // go to full screen + break; + + case svc_finale: + cl.intermission = 2; + cl.completed_time = (int)cl.time; + vid.recalc_refdef = true; // go to full screen + SCR_CenterPrint (MSG_ReadString ()); + break; + + case svc_cutscene: + cl.intermission = 3; + cl.completed_time = (int)cl.time; + vid.recalc_refdef = true; // go to full screen + SCR_CenterPrint (MSG_ReadString ()); + break; + + case svc_sellscreen: + Cmd_ExecuteString ("help", src_command); + break; + } + } + +// if(sv.active) +// GpError("CL_ParseServerMessage done",5); +} + +#ifdef USEFPM +void CL_ParseServerMessageFPM (void) +{ + int cmd; + int i; + +// +// if recording demos, copy the message out +// + if (cl_shownet.value == 1) + Con_Printf ("%i ",net_message.cursize); + else if (cl_shownet.value == 2) + Con_Printf ("------------------\n"); + + cl.onground = false; // unless the server says otherwise +// +// parse the message +// + MSG_BeginReading (); + + while (1) + { + if (msg_badread) + Host_Error ("CL_ParseServerMessage: Bad server message"); + + cmd = MSG_ReadByte (); + + if (cmd == -1) + { + SHOWNET("END OF MESSAGE"); + return; // end of message + } + + // if the high bit of the command byte is set, it is a fast update + if (cmd & 128) + { + SHOWNET("fast update"); + CL_ParseUpdateFPM (cmd&127); + continue; + } + + SHOWNET(svc_strings[cmd]); + + // other commands + switch (cmd) + { + default: + Host_Error ("CL_ParseServerMessage: Illegible server message\n"); + break; + + case svc_nop: +// Con_Printf ("svc_nop\n"); + break; + + case svc_time: + clFPM.mtime[1] = clFPM.mtime[0]; + clFPM.mtime[0] = MSG_ReadFloat (); + break; + + case svc_clientdata: + i = MSG_ReadShort (); + CL_ParseClientdataFPM (i); + break; + + case svc_version: + i = MSG_ReadLong (); + if (i != PROTOCOL_VERSION) + Host_Error ("CL_ParseServerMessage: Server is protocol %i instead of %i\n", i, PROTOCOL_VERSION); + break; + + case svc_disconnect: + Host_EndGame ("Server disconnected\n"); + + case svc_print: + Con_Printf ("%s", MSG_ReadString ()); + break; + + case svc_centerprint: + SCR_CenterPrint (MSG_ReadString ()); + break; + + case svc_stufftext: + Cbuf_AddText (MSG_ReadString ()); + break; + + case svc_damage: + V_ParseDamageFPM (); + break; + + case svc_serverinfo: + CL_ParseServerInfoFPM (); + vid.recalc_refdef = true; // leave intermission full screen + break; + + case svc_setangle: + for (i=0 ; i<3 ; i++) + clFPM.viewangles[i] = FPM_FROMFLOAT(MSG_ReadAngle ()); + break; + + case svc_setview: + clFPM.viewentity = MSG_ReadShort (); + break; + + case svc_lightstyle: + i = MSG_ReadByte (); + if (i >= MAX_LIGHTSTYLES) + Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); + Q_strcpy (cl_lightstyle[i].map, MSG_ReadString()); + cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map); + break; + + case svc_sound: + //Dan: TODO: Convert func to FPM + CL_ParseStartSoundPacket(); + break; + + case svc_stopsound: + i = MSG_ReadShort(); + S_StopSound(i>>3, i&7); + break; + + case svc_updatename: + Sbar_Changed (); + i = MSG_ReadByte (); + if (i >= clFPM.maxclients) + Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD"); + strcpy (clFPM.scores[i].name, MSG_ReadString ()); + break; + + case svc_updatefrags: + Sbar_Changed (); + i = MSG_ReadByte (); + if (i >= clFPM.maxclients) + Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD"); + clFPM.scores[i].frags = MSG_ReadShort (); + break; + + case svc_updatecolors: + Sbar_Changed (); + i = MSG_ReadByte (); + if (i >= clFPM.maxclients) + Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD"); + clFPM.scores[i].colors = MSG_ReadByte (); + CL_NewTranslationFPM (i); + break; + + case svc_particle: + R_ParseParticleEffectFPM (); + break; + + case svc_spawnbaseline: + i = MSG_ReadShort (); + // must use CL_EntityNum() to force cl.num_entities up + CL_ParseBaselineFPM (CL_EntityNumFPM(i)); + break; + case svc_spawnstatic: + CL_ParseStaticFPM (); + break; + case svc_temp_entity: + CL_ParseTEntFPM (); + break; + + case svc_setpause: + { + clFPM.paused = MSG_ReadByte (); + + if (clFPM.paused) + { + CDAudio_Pause (); +#ifdef _WIN32 + VID_HandlePause (true); +#endif + } + else + { + CDAudio_Resume (); +#ifdef _WIN32 + VID_HandlePause (false); +#endif + } + } + break; + + case svc_signonnum: + i = MSG_ReadByte (); + if (i <= cls.signon) + Host_Error ("Received signon %i when at %i", i, cls.signon); + cls.signon = i; + CL_SignonReply (); + break; + + case svc_killedmonster: + clFPM.stats[STAT_MONSTERS]++; + break; + + case svc_foundsecret: + clFPM.stats[STAT_SECRETS]++; + break; + + case svc_updatestat: + i = MSG_ReadByte (); + if (i < 0 || i >= MAX_CL_STATS) + Sys_Error ("svc_updatestat: %i is invalid", i); + clFPM.stats[i] = MSG_ReadLong ();; + break; + + case svc_spawnstaticsound: + CL_ParseStaticSound (); + break; + + case svc_cdtrack: + clFPM.cdtrack = MSG_ReadByte (); + clFPM.looptrack = MSG_ReadByte (); + if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) + CDAudio_Play ((byte)cls.forcetrack, true); + else + CDAudio_Play ((byte)clFPM.cdtrack, true); + break; + + case svc_intermission: + clFPM.intermission = 1; + clFPM.completed_time = (int)clFPM.time; + vid.recalc_refdef = true; // go to full screen + break; + + case svc_finale: + clFPM.intermission = 2; + clFPM.completed_time = (int)clFPM.time; + vid.recalc_refdef = true; // go to full screen + SCR_CenterPrint (MSG_ReadString ()); + break; + + case svc_cutscene: + clFPM.intermission = 3; + clFPM.completed_time = (int)clFPM.time; + vid.recalc_refdef = true; // go to full screen + SCR_CenterPrint (MSG_ReadString ()); + break; + + case svc_sellscreen: + Cmd_ExecuteString ("help", src_command); + break; + } + } +} +#endif diff --git a/project/jni/application/quake/source/cl_tent.c b/project/jni/application/quake/source/cl_tent.c new file mode 100644 index 000000000..02cf7d20f --- /dev/null +++ b/project/jni/application/quake/source/cl_tent.c @@ -0,0 +1,713 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cl_tent.c -- client side temporary entities + +#include "quakedef.h" + +int num_temp_entities; +entity_t cl_temp_entities[MAX_TEMP_ENTITIES]; +beam_t cl_beams[MAX_BEAMS]; + +#ifdef USEFPM +entity_FPM_t cl_temp_entitiesFPM[MAX_TEMP_ENTITIES]; +beam_FPM_t cl_beamsFPM[MAX_BEAMS]; +#endif + +sfx_t *cl_sfx_wizhit; +sfx_t *cl_sfx_knighthit; +sfx_t *cl_sfx_tink1; +sfx_t *cl_sfx_ric1; +sfx_t *cl_sfx_ric2; +sfx_t *cl_sfx_ric3; +sfx_t *cl_sfx_r_exp3; +#ifdef QUAKE2 +sfx_t *cl_sfx_imp; +sfx_t *cl_sfx_rail; +#endif + +/* +================= +CL_ParseTEnt +================= +*/ +void CL_InitTEnts (void) +{ + cl_sfx_wizhit = S_PrecacheSound ("wizard/hit.wav"); + cl_sfx_knighthit = S_PrecacheSound ("hknight/hit.wav"); + cl_sfx_tink1 = S_PrecacheSound ("weapons/tink1.wav"); + cl_sfx_ric1 = S_PrecacheSound ("weapons/ric1.wav"); + cl_sfx_ric2 = S_PrecacheSound ("weapons/ric2.wav"); + cl_sfx_ric3 = S_PrecacheSound ("weapons/ric3.wav"); + cl_sfx_r_exp3 = S_PrecacheSound ("weapons/r_exp3.wav"); +#ifdef QUAKE2 + cl_sfx_imp = S_PrecacheSound ("shambler/sattck1.wav"); + cl_sfx_rail = S_PrecacheSound ("weapons/lstart.wav"); +#endif +} + +/* +================= +CL_ParseBeam +================= +*/ +void CL_ParseBeam (model_t *m) +{ + int ent; + vec3_t start, end; + beam_t *b; + int i; + + ent = MSG_ReadShort (); + + start[0] = MSG_ReadCoord (); + start[1] = MSG_ReadCoord (); + start[2] = MSG_ReadCoord (); + + end[0] = MSG_ReadCoord (); + end[1] = MSG_ReadCoord (); + end[2] = MSG_ReadCoord (); + +// override any beam with the same entity + for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) + if (b->entity == ent) + { + b->entity = ent; + b->model = m; + b->endtime = (float)(cl.time + 0.2); + VectorCopy (start, b->start); + VectorCopy (end, b->end); + return; + } + +// find a free beam + for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) + { + if (!b->model || b->endtime < cl.time) + { + b->entity = ent; + b->model = m; + b->endtime = (float)(cl.time + 0.2); + VectorCopy (start, b->start); + VectorCopy (end, b->end); + return; + } + } + Con_Printf ("beam list overflow!\n"); +} + +#ifdef USEFPM +void CL_ParseBeamFPM (model_FPM_t *m) +{ + int ent; + vec3_FPM_t start, end; + beam_FPM_t *b; + int i; + + ent = MSG_ReadShort (); + + start[0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + start[1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + start[2] = FPM_FROMFLOAT(MSG_ReadCoord ()); + + end[0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + end[1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + end[2] = FPM_FROMFLOAT(MSG_ReadCoord ()); + +// override any beam with the same entity + for (i=0, b=cl_beamsFPM ; i< MAX_BEAMS ; i++, b++) + if (b->entity == ent) + { + b->entity = ent; + b->model = m; + b->endtime = (float)(clFPM.time + 0.2); + VectorCopy (start, b->start); + VectorCopy (end, b->end); + return; + } + +// find a free beam + for (i=0, b=cl_beamsFPM ; i< MAX_BEAMS ; i++, b++) + { + if (!b->model || b->endtime < clFPM.time) + { + b->entity = ent; + b->model = m; + b->endtime = (float)(clFPM.time + 0.2); + VectorCopy (start, b->start); + VectorCopy (end, b->end); + return; + } + } + Con_Printf ("beam list overflow!\n"); +} +#endif + +/* +================= +CL_ParseTEnt +================= +*/ +void CL_ParseTEnt (void) +{ + int type; + vec3_t pos; +#ifdef QUAKE2 + vec3_t endpos; +#endif + dlight_t *dl; + int rnd; + int colorStart, colorLength; + + type = MSG_ReadByte (); + switch (type) + { + case TE_WIZSPIKE: // spike hitting wall + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_RunParticleEffect (pos, vec3_origin, 20, 30); + S_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1); + break; + + case TE_KNIGHTSPIKE: // spike hitting wall + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_RunParticleEffect (pos, vec3_origin, 226, 20); + S_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1); + break; + + case TE_SPIKE: // spike hitting wall + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); +#ifdef GLTEST + Test_Spawn (pos); +#else + R_RunParticleEffect (pos, vec3_origin, 0, 10); +#endif + if ( rand() % 5 ) + S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1); + else + { + rnd = rand() & 3; + if (rnd == 1) + S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1); + else if (rnd == 2) + S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1); + else + S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1); + } + break; + case TE_SUPERSPIKE: // super spike hitting wall + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_RunParticleEffect (pos, vec3_origin, 0, 20); + + if ( rand() % 5 ) + S_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1); + else + { + rnd = rand() & 3; + if (rnd == 1) + S_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1); + else if (rnd == 2) + S_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1); + else + S_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1); + } + break; + + case TE_GUNSHOT: // bullet hitting wall + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_RunParticleEffect (pos, vec3_origin, 0, 20); + break; + + case TE_EXPLOSION: // rocket explosion + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_ParticleExplosion (pos); + dl = CL_AllocDlight (0); + VectorCopy (pos, dl->origin); + dl->radius = 350; + dl->die = (float)(cl.time + 0.5); + dl->decay = 300; + S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); + break; + + case TE_TAREXPLOSION: // tarbaby explosion + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_BlobExplosion (pos); + + S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); + break; + + case TE_LIGHTNING1: // lightning bolts + CL_ParseBeam (Mod_ForName("progs/bolt.mdl", true)); + break; + + case TE_LIGHTNING2: // lightning bolts + CL_ParseBeam (Mod_ForName("progs/bolt2.mdl", true)); + break; + + case TE_LIGHTNING3: // lightning bolts + CL_ParseBeam (Mod_ForName("progs/bolt3.mdl", true)); + break; + +// PGM 01/21/97 + case TE_BEAM: // grappling hook beam + CL_ParseBeam (Mod_ForName("progs/beam.mdl", true)); + break; +// PGM 01/21/97 + + case TE_LAVASPLASH: + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_LavaSplash (pos); + break; + + case TE_TELEPORT: + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + R_TeleportSplash (pos); + break; + + case TE_EXPLOSION2: // color mapped explosion + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + colorStart = MSG_ReadByte (); + colorLength = MSG_ReadByte (); + R_ParticleExplosion2 (pos, colorStart, colorLength); + dl = CL_AllocDlight (0); + VectorCopy (pos, dl->origin); + dl->radius = 350; + dl->die = (float)(cl.time + 0.5); + dl->decay = 300; + S_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1); + break; + +#ifdef QUAKE2 + case TE_IMPLOSION: + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + S_StartSound (-1, 0, cl_sfx_imp, pos, 1, 1); + break; + + case TE_RAILTRAIL: + pos[0] = MSG_ReadCoord (); + pos[1] = MSG_ReadCoord (); + pos[2] = MSG_ReadCoord (); + endpos[0] = MSG_ReadCoord (); + endpos[1] = MSG_ReadCoord (); + endpos[2] = MSG_ReadCoord (); + S_StartSound (-1, 0, cl_sfx_rail, pos, 1, 1); + S_StartSound (-1, 1, cl_sfx_r_exp3, endpos, 1, 1); + R_RocketTrail (pos, endpos, 0+128); + R_ParticleExplosion (endpos); + dl = CL_AllocDlight (-1); + VectorCopy (endpos, dl->origin); + dl->radius = 350; + dl->die = cl.time + 0.5; + dl->decay = 300; + break; +#endif + + default: + Sys_Error ("CL_ParseTEnt: bad type"); + } +} + +#ifdef USEFPM +void CL_ParseTEntFPM (void) +{ + int type; + vec3_FPM_t pos; +#ifdef QUAKE2 + vec3_FPM_t endpos; +#endif + dlight_FPM_t *dl; + int rnd; + int colorStart, colorLength; + + type = MSG_ReadByte (); + switch (type) + { + case TE_WIZSPIKE: // spike hitting wall + pos[0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[2] = FPM_FROMFLOAT(MSG_ReadCoord ()); + R_RunParticleEffectFPM (pos, vec3_originFPM, 20, 30); + S_StartSoundFPM (-1, 0, cl_sfx_wizhit, pos, 1, 1); + break; + + case TE_KNIGHTSPIKE: // spike hitting wall + pos[0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[2] = FPM_FROMFLOAT(MSG_ReadCoord ()); + R_RunParticleEffectFPM (pos, vec3_originFPM, 226, 20); + S_StartSoundFPM (-1, 0, cl_sfx_knighthit, pos, 1, 1); + break; + + case TE_SPIKE: // spike hitting wall + pos[0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[2] = FPM_FROMFLOAT(MSG_ReadCoord ()); +#ifdef GLTEST + Test_Spawn (pos); +#else + R_RunParticleEffectFPM (pos, vec3_originFPM, 0, 10); +#endif + if ( rand() % 5 ) + S_StartSoundFPM (-1, 0, cl_sfx_tink1, pos, 1, 1); + else + { + rnd = rand() & 3; + if (rnd == 1) + S_StartSoundFPM (-1, 0, cl_sfx_ric1, pos, 1, 1); + else if (rnd == 2) + S_StartSoundFPM (-1, 0, cl_sfx_ric2, pos, 1, 1); + else + S_StartSoundFPM (-1, 0, cl_sfx_ric3, pos, 1, 1); + } + break; + case TE_SUPERSPIKE: // super spike hitting wall + pos[0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[2] = FPM_FROMFLOAT(MSG_ReadCoord ()); + R_RunParticleEffectFPM (pos, vec3_originFPM, 0, 20); + + if ( rand() % 5 ) + S_StartSoundFPM (-1, 0, cl_sfx_tink1, pos, 1, 1); + else + { + rnd = rand() & 3; + if (rnd == 1) + S_StartSoundFPM (-1, 0, cl_sfx_ric1, pos, 1, 1); + else if (rnd == 2) + S_StartSoundFPM (-1, 0, cl_sfx_ric2, pos, 1, 1); + else + S_StartSoundFPM (-1, 0, cl_sfx_ric3, pos, 1, 1); + } + break; + + case TE_GUNSHOT: // bullet hitting wall + pos[0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[2] = FPM_FROMFLOAT(MSG_ReadCoord ()); + R_RunParticleEffectFPM (pos, vec3_originFPM, 0, 20); + break; + + case TE_EXPLOSION: // rocket explosion + pos[0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[2] = FPM_FROMFLOAT(MSG_ReadCoord ()); + R_ParticleExplosionFPM (pos); + dl = CL_AllocDlightFPM (0); + VectorCopy (pos, dl->origin); + dl->radius = 350; + dl->die = FPM_ADD(FPM_FROMFLOAT(cl.time), FPM_FROMFLOAT(0.5)); + dl->decay = 300; + S_StartSoundFPM (-1, 0, cl_sfx_r_exp3, pos, 1, 1); + break; + + case TE_TAREXPLOSION: // tarbaby explosion + pos[0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[2] = FPM_FROMFLOAT(MSG_ReadCoord ()); + R_BlobExplosionFPM (pos); + + S_StartSoundFPM (-1, 0, cl_sfx_r_exp3, pos, 1, 1); + break; + + case TE_LIGHTNING1: // lightning bolts + CL_ParseBeamFPM (Mod_ForNameFPM("progs/bolt.mdl", true)); + break; + + case TE_LIGHTNING2: // lightning bolts + CL_ParseBeamFPM (Mod_ForNameFPM("progs/bolt2.mdl", true)); + break; + + case TE_LIGHTNING3: // lightning bolts + CL_ParseBeamFPM (Mod_ForNameFPM("progs/bolt3.mdl", true)); + break; + +// PGM 01/21/97 + case TE_BEAM: // grappling hook beam + CL_ParseBeamFPM (Mod_ForNameFPM("progs/beam.mdl", true)); + break; +// PGM 01/21/97 + + case TE_LAVASPLASH: + pos[0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[2] = FPM_FROMFLOAT(MSG_ReadCoord ()); + R_LavaSplashFPM (pos); + break; + + case TE_TELEPORT: + pos[0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[2] = FPM_FROMFLOAT(MSG_ReadCoord ()); + R_TeleportSplashFPM (pos); + break; + + case TE_EXPLOSION2: // color mapped explosion + pos[0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[2] = FPM_FROMFLOAT(MSG_ReadCoord ()); + colorStart = MSG_ReadByte (); + colorLength = MSG_ReadByte (); + R_ParticleExplosion2FPM (pos, colorStart, colorLength); + dl = CL_AllocDlightFPM (0); + VectorCopy (pos, dl->origin); + dl->radius = 350; + dl->die = FPM_ADD(FPM_FROMFLOAT(cl.time), FPM_FROMFLOAT(0.5)); + dl->decay = 300; + S_StartSoundFPM (-1, 0, cl_sfx_r_exp3, pos, 1, 1); + break; + +#ifdef QUAKE2 + case TE_IMPLOSION: + pos[0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[2] = FPM_FROMFLOAT(MSG_ReadCoord ()); + S_StartSoundFPM (-1, 0, cl_sfx_imp, pos, 1, 1); + break; + + case TE_RAILTRAIL: + pos[0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + pos[2] = FPM_FROMFLOAT(MSG_ReadCoord ()); + endpos[0] = FPM_FROMFLOAT(MSG_ReadCoord ()); + endpos[1] = FPM_FROMFLOAT(MSG_ReadCoord ()); + endpos[2] = FPM_FROMFLOAT(MSG_ReadCoord ()); + S_StartSoundFPM (-1, 0, cl_sfx_rail, pos, 1, 1); + S_StartSoundFPM (-1, 1, cl_sfx_r_exp3, endpos, 1, 1); + R_RocketTrailFPM (pos, endpos, 0+128); + R_ParticleExplosionFPM (endpos); + dl = CL_AllocDlightFPM (-1); + VectorCopy (endpos, dl->origin); + dl->radius = 350; + dl->die = FPM_ADD(FPM_FROMFLOAT(cl.time), FPM_FROMFLOAT(0.5)); + dl->decay = 300; + break; +#endif + + default: + Sys_Error ("CL_ParseTEnt: bad type"); + } +} +#endif + +/* +================= +CL_NewTempEntity +================= +*/ +entity_t *CL_NewTempEntity (void) +{ + entity_t *ent; + + if (cl_numvisedicts == MAX_VISEDICTS) + return NULL; + if (num_temp_entities == MAX_TEMP_ENTITIES) + return NULL; + ent = &cl_temp_entities[num_temp_entities]; + Q_memset (ent, 0, sizeof(*ent)); + num_temp_entities++; + cl_visedicts[cl_numvisedicts] = ent; + cl_numvisedicts++; + + ent->colormap = vid.colormap; + return ent; +} + +#ifdef USEFPM +entity_FPM_t *CL_NewTempEntityFPM (void) +{ + entity_FPM_t *ent; + + if (cl_numvisedicts == MAX_VISEDICTS) + return NULL; + if (num_temp_entities == MAX_TEMP_ENTITIES) + return NULL; + ent = &cl_temp_entitiesFPM[num_temp_entities]; + Q_memset (ent, 0, sizeof(*ent)); + num_temp_entities++; + cl_visedictsFPM[cl_numvisedicts] = ent; + cl_numvisedicts++; + + ent->colormap = vid.colormap; + return ent; +} +#endif +/* +================= +CL_UpdateTEnts +================= +*/ +void CL_UpdateTEnts (void) +{ + int i; + beam_t *b; + vec3_t dist, org; + float d; + entity_t *ent; + float yaw, pitch; + float forward; + + num_temp_entities = 0; + +// update lightning + for (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++) + { + if (!b->model || b->endtime < cl.time) + continue; + + // if coming from the player, update the start position + if (b->entity == cl.viewentity) + { + VectorCopy (cl_entities[cl.viewentity].origin, b->start); + } + + // calculate pitch and yaw + VectorSubtract (b->end, b->start, dist); + + if (dist[1] == 0 && dist[0] == 0) + { + yaw = 0; + if (dist[2] > 0) + pitch = 90; + else + pitch = 270; + } + else + { + yaw = (float)(int) (atan2(dist[1], dist[0]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + + forward = (float)sqrt (dist[0]*dist[0] + dist[1]*dist[1]); + pitch = (float)(int) (atan2(dist[2], forward) * 180 / M_PI); + if (pitch < 0) + pitch += 360; + } + + // add new entities for the lightning + VectorCopy (b->start, org); + d = VectorNormalize(dist); + while (d > 0) + { + ent = CL_NewTempEntity (); + if (!ent) + return; + VectorCopy (org, ent->origin); + ent->model = b->model; + ent->angles[0] = pitch; + ent->angles[1] = yaw; + ent->angles[2] = (float)(rand()%360); + + for (i=0 ; i<3 ; i++) + org[i] += dist[i]*30; + d -= 30; + } + } + +} + +#ifdef USEFPM +void CL_UpdateTEntsFPM (void) +{ + int i; + beam_FPM_t *b; + vec3_FPM_t dist, org; + fixedpoint_t d; + entity_FPM_t *ent; + fixedpoint_t yaw, pitch; + fixedpoint_t forward; + + num_temp_entities = 0; + +// update lightning + for (i=0, b=cl_beamsFPM ; i< MAX_BEAMS ; i++, b++) + { + if (!b->model || b->endtime < clFPM.time) + continue; + + // if coming from the player, update the start position + if (b->entity == clFPM.viewentity) + { + VectorCopy (cl_entitiesFPM[clFPM.viewentity].origin, b->start); + } + + // calculate pitch and yaw + VectorSubtractFPM (b->end, b->start, dist); + + if (dist[1] == 0 && dist[0] == 0) + { + yaw = 0; + if (dist[2] > 0) + pitch = FPM_FROMLONG(90); + else + pitch = FPM_FROMLONG(270); + } + else + { + yaw = FPM_DIV(FPM_MUL(FPM_FROMFLOAT(atan2(dist[1], dist[0])), FPM_FROMLONG(180)), FPM_PI); + if (yaw < 0) + yaw = FPM_ADD(yaw, FPM_FROMLONG(360)); + + forward = FPM_SQRT(FPM_ADD(FPM_SQR(dist[0]), FPM_SQR(dist[1]))); + pitch = FPM_DIV(FPM_MUL(FPM_FROMFLOAT(atan2(dist[2], forward)), FPM_FROMLONG(180)), FPM_PI); + if (pitch < 0) + pitch = FPM_ADD(pitch, FPM_FROMLONG(360)); + } + + // add new entities for the lightning + VectorCopy (b->start, org); + d = VectorNormalizeFPM(dist); + while (d > 0) + { + ent = CL_NewTempEntityFPM (); + if (!ent) + return; + VectorCopy (org, ent->origin); + ent->model = b->model; + ent->angles[0] = pitch; + ent->angles[1] = yaw; + ent->angles[2] = FPM_FROMLONG(rand()%360); + + for (i=0 ; i<3 ; i++) + org[i] = FPM_ADD(org[i], FPM_MUL(dist[i], FPM_FROMLONG(30))); + d = FPM_SUB(d, FPM_FROMLONG(30)); + } + } +} +#endif diff --git a/project/jni/application/quake/source/client.h b/project/jni/application/quake/source/client.h new file mode 100644 index 000000000..4acebd522 --- /dev/null +++ b/project/jni/application/quake/source/client.h @@ -0,0 +1,530 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// client.h + +typedef struct +{ + vec3_t viewangles; + +// intended velocities + float forwardmove; + float sidemove; + float upmove; +#ifdef QUAKE2 + byte lightlevel; +#endif +} usercmd_t; + +typedef struct +{ + vec3_FPM_t viewangles; + +// intended velocities + fixedpoint_t forwardmove; + fixedpoint_t sidemove; + fixedpoint_t upmove; +#ifdef QUAKE2 + byte lightlevel; +#endif +} usercmd_FPM_t; + +typedef struct +{ + int length; + char map[MAX_STYLESTRING]; +} lightstyle_t; + +typedef struct +{ + char name[MAX_SCOREBOARDNAME]; + float entertime; + int frags; + int colors; // two 4 bit fields + byte translations[VID_GRADES*256]; +} scoreboard_t; + +typedef struct +{ + int destcolor[3]; + int percent; // 0-256 +} cshift_t; + +#define CSHIFT_CONTENTS 0 +#define CSHIFT_DAMAGE 1 +#define CSHIFT_BONUS 2 +#define CSHIFT_POWERUP 3 +#define NUM_CSHIFTS 4 + +#define NAME_LENGTH 64 + + +// +// client_state_t should hold all pieces of the client state +// + +#define SIGNONS 4 // signon messages to receive before connected + +#define MAX_DLIGHTS 32 +typedef struct +{ + vec3_t origin; + float radius; + float die; // stop lighting after this time + float decay; // drop this each second + float minlight; // don't add when contributing less + int key; +#ifdef QUAKE2 + qboolean dark; // subtracts light instead of adding +#endif +} dlight_t; + +typedef struct +{ + vec3_FPM_t origin; + fixedpoint_t radius; + fixedpoint_t die; // stop lighting after this time + fixedpoint_t decay; // drop this each second + fixedpoint_t minlight; // don't add when contributing less + int key; +#ifdef QUAKE2 + qboolean dark; // subtracts light instead of adding +#endif +} dlight_FPM_t; + + +#define MAX_BEAMS 24 +typedef struct +{ + int entity; + struct model_s *model; + float endtime; + vec3_t start, end; +} beam_t; + +typedef struct +{ + int entity; + struct model_FPM_s *model; + float endtime; + vec3_FPM_t start, end; +} beam_FPM_t; + +#define MAX_EFRAGS 640 + +#define MAX_MAPSTRING 2048 +#define MAX_DEMOS 8 +#define MAX_DEMONAME 16 + +typedef enum { +ca_dedicated, // a dedicated server with no ability to start a client +ca_disconnected, // full screen console with no connection +ca_connected // valid netcon, talking to a server +} cactive_t; + +// +// the client_static_t structure is persistant through an arbitrary number +// of server connections +// +typedef struct +{ + cactive_t state; + +// personalization data sent to server + char mapstring[MAX_QPATH]; + char spawnparms[MAX_MAPSTRING]; // to restart a level + +// demo loop control + int demonum; // -1 = don't play demos + char demos[MAX_DEMOS][MAX_DEMONAME]; // when not playing + +// demo recording info must be here, because record is started before +// entering a map (and clearing client_state_t) + qboolean demorecording; + qboolean demoplayback; + qboolean timedemo; + int forcetrack; // -1 = use normal cd track + FILE *demofile; + int td_lastframe; // to meter out one message a frame + int td_startframe; // host_framecount at start + float td_starttime; // realtime at second frame of timedemo + + +// connection information + int signon; // 0 to SIGNONS + struct qsocket_s *netcon; + sizebuf_t message; // writing buffer to send to server + +} client_static_t; + +extern client_static_t cls; + +// +// the client_state_t structure is wiped completely at every +// server signon +// +typedef struct +{ + int movemessages; // since connecting to this server + // throw out the first couple, so the player + // doesn't accidentally do something the + // first frame + usercmd_t cmd; // last command sent to the server + +// information for local display + int stats[MAX_CL_STATS]; // health, etc + int items; // inventory bit flags + float item_gettime[32]; // cl.time of aquiring item, for blinking + float faceanimtime; // use anim frame if cl.time < this + + cshift_t cshifts[NUM_CSHIFTS]; // color shifts for damage, powerups + cshift_t prev_cshifts[NUM_CSHIFTS]; // and content types + +// the client maintains its own idea of view angles, which are +// sent to the server each frame. The server sets punchangle when +// the view is temporarliy offset, and an angle reset commands at the start +// of each level and after teleporting. + vec3_t mviewangles[2]; // during demo playback viewangles is lerped + // between these + vec3_t viewangles; + + vec3_t mvelocity[2]; // update by server, used for lean+bob + // (0 is newest) + vec3_t velocity; // lerped between mvelocity[0] and [1] + + vec3_t punchangle; // temporary offset + +// pitch drifting vars + float idealpitch; + float pitchvel; + qboolean nodrift; + float driftmove; + double laststop; + + float viewheight; + float crouch; // local amount for smoothing stepups + + qboolean paused; // send over by server + qboolean onground; + qboolean inwater; + + int intermission; // don't change view angle, full screen, etc + int completed_time; // latched at intermission start + + double mtime[2]; // the timestamp of last two messages + double time; // clients view of time, should be between + // servertime and oldservertime to generate + // a lerp point for other data + double oldtime; // previous cl.time, time-oldtime is used + // to decay light values and smooth step ups + + + float last_received_message; // (realtime) for net trouble icon + +// +// information that is static for the entire time connected to a server +// + struct model_s *model_precache[MAX_MODELS]; + struct sfx_s *sound_precache[MAX_SOUNDS]; + + char levelname[40]; // for display on solo scoreboard + int viewentity; // cl_entitites[cl.viewentity] = player + int maxclients; + int gametype; + +// refresh related state + struct model_s *worldmodel; // cl_entitites[0].model + struct efrag_s *free_efrags; + int num_entities; // held in cl_entities array + int num_statics; // held in cl_staticentities array + entity_t viewent; // the gun model + + int cdtrack, looptrack; // cd audio + +// frag scoreboard + scoreboard_t *scores; // [cl.maxclients] + +#ifdef QUAKE2 +// light level at player's position including dlights +// this is sent back to the server each frame +// architectually ugly but it works + int light_level; +#endif +} client_state_t; + +typedef struct +{ + int movemessages; // since connecting to this server + // throw out the first couple, so the player + // doesn't accidentally do something the + // first frame + usercmd_FPM_t cmd; // last command sent to the server + +// information for local display + int stats[MAX_CL_STATS]; // health, etc + int items; // inventory bit flags + float item_gettime[32]; // cl.time of aquiring item, for blinking + float faceanimtime; // use anim frame if cl.time < this + + cshift_t cshifts[NUM_CSHIFTS]; // color shifts for damage, powerups + cshift_t prev_cshifts[NUM_CSHIFTS]; // and content types + +// the client maintains its own idea of view angles, which are +// sent to the server each frame. The server sets punchangle when +// the view is temporarliy offset, and an angle reset commands at the start +// of each level and after teleporting. + vec3_FPM_t mviewangles[2]; // during demo playback viewangles is lerped + // between these + vec3_FPM_t viewangles; + + vec3_FPM_t mvelocity[2]; // update by server, used for lean+bob + // (0 is newest) + vec3_FPM_t velocity; // lerped between mvelocity[0] and [1] + + vec3_FPM_t punchangle; // temporary offset + +// pitch drifting vars + fixedpoint_t idealpitch; + fixedpoint_t pitchvel; + qboolean nodrift; + fixedpoint_t driftmove; + double laststop; + + fixedpoint_t viewheight; + fixedpoint_t crouch; // local amount for smoothing stepups + + qboolean paused; // send over by server + qboolean onground; + qboolean inwater; + + int intermission; // don't change view angle, full screen, etc + int completed_time; // latched at intermission start + + double mtime[2]; // the timestamp of last two messages + double time; // clients view of time, should be between + // servertime and oldservertime to generate + // a lerp point for other data + double oldtime; // previous cl.time, time-oldtime is used + // to decay light values and smooth step ups + + + float last_received_message; // (realtime) for net trouble icon + +// +// information that is static for the entire time connected to a server +// + struct model_FPM_s *model_precache[MAX_MODELS]; + struct sfx_s *sound_precache[MAX_SOUNDS]; + + char levelname[40]; // for display on solo scoreboard + int viewentity; // cl_entitites[cl.viewentity] = player + int maxclients; + int gametype; + +// refresh related state + struct model_FPM_s *worldmodel; // cl_entitites[0].model + struct efrag_FPM_s *free_efrags; + int num_entities; // held in cl_entities array + int num_statics; // held in cl_staticentities array + entity_FPM_t viewent; // the gun model + + int cdtrack, looptrack; // cd audio + +// frag scoreboard + scoreboard_t *scores; // [cl.maxclients] + +#ifdef QUAKE2 +// light level at player's position including dlights +// this is sent back to the server each frame +// architectually ugly but it works + int light_level; +#endif +} client_state_FPM_t; + + +// +// cvars +// +extern cvar_t command; + +extern cvar_t cl_name; +extern cvar_t cl_color; + +extern cvar_t cl_upspeed; +extern cvar_t cl_forwardspeed; +extern cvar_t cl_backspeed; +extern cvar_t cl_sidespeed; + +extern cvar_t cl_movespeedkey; + +extern cvar_t cl_yawspeed; +extern cvar_t cl_pitchspeed; + +extern cvar_t cl_anglespeedkey; + +extern cvar_t cl_autofire; + +extern cvar_t cl_showfps;// 2001-11-31 FPS display by QuakeForge/Muff +extern int fps_count;// 2001-11-31 FPS display by QuakeForge/Muff +extern cvar_t cl_shownet; +extern cvar_t cl_nolerp; + +extern cvar_t cl_pitchdriftspeed; +extern cvar_t lookspring; +extern cvar_t lookstrafe; +extern cvar_t sensitivity; + +extern cvar_t cl_config; + +extern cvar_t doublesizeset; +extern cvar_t doublesizestatus; + +extern cvar_t m_pitch; +extern cvar_t m_yaw; +extern cvar_t m_forward; +extern cvar_t m_side; + + +#define MAX_TEMP_ENTITIES 64 // lightning bolts, etc +#define MAX_STATIC_ENTITIES 128 // torches, etc + +extern client_state_t cl; +extern client_state_FPM_t clFPM; + +// FIXME, allocate dynamically +extern efrag_t cl_efrags[MAX_EFRAGS]; +extern entity_t cl_entities[MAX_EDICTS]; +extern entity_FPM_t cl_entitiesFPM[MAX_EDICTS]; +extern entity_t cl_static_entities[MAX_STATIC_ENTITIES]; +extern entity_FPM_t cl_static_entitiesFPM[MAX_STATIC_ENTITIES]; +extern lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES]; +extern dlight_t cl_dlights[MAX_DLIGHTS]; +extern dlight_FPM_t cl_dlightsFPM[MAX_DLIGHTS]; +extern entity_t cl_temp_entities[MAX_TEMP_ENTITIES]; +extern entity_FPM_t cl_temp_entitiesFPM[MAX_TEMP_ENTITIES]; +extern beam_t cl_beams[MAX_BEAMS]; +extern beam_FPM_t cl_beamsFPM[MAX_BEAMS]; + +//============================================================================= + +// +// cl_main +// +dlight_t *CL_AllocDlight (int key); +dlight_FPM_t *CL_AllocDlightFPM (int key); +void CL_DecayLights (void); +void CL_DecayLightsFPM (void); + +void CL_Init (void); + +void CL_EstablishConnection (char *host); +void CL_EstablishConnectionFPM (char *host); +void CL_Signon1 (void); +void CL_Signon2 (void); +void CL_Signon3 (void); +void CL_Signon4 (void); + +void CL_Disconnect (void); +void CL_DisconnectFPM (void); +void CL_Disconnect_f (void); +void CL_Disconnect_FPM_f (void); +void CL_NextDemo (void); + +#define MAX_VISEDICTS 256 +extern int cl_numvisedicts; +extern entity_t *cl_visedicts[MAX_VISEDICTS]; +extern entity_FPM_t *cl_visedictsFPM[MAX_VISEDICTS]; + +// +// cl_input +// +typedef struct +{ + int down[2]; // key nums holding it down + int state; // low bit is down state +} kbutton_t; + +extern kbutton_t in_mlook, in_klook; +extern kbutton_t in_strafe; +extern kbutton_t in_speed; + +void CL_InitInput (void); +void CL_SendCmd (void); +void CL_SendMove (usercmd_t *cmd); +void CL_SendMoveFPM (usercmd_FPM_t *cmd); + +void CL_ParseTEnt (void); +void CL_ParseTEntFPM (void); +void CL_UpdateTEnts (void); +void CL_UpdateTEntsFPM (void); + +void CL_ClearState (void); +void CL_ClearStateFPM (void); + +int CL_ReadFromServer (void); +int CL_ReadFromServerFPM (void); +void CL_WriteToServer (usercmd_t *cmd); +void CL_BaseMove (usercmd_t *cmd); +void CL_BaseMoveFPM (usercmd_FPM_t *cmd); +int CL_GetMessage(); + +float CL_KeyState (kbutton_t *key); +char *Key_KeynumToString (int keynum); + +// +// cl_demo.c +// +void CL_StopPlayback (void); +int CL_GetMessageFPM (void); + +void CL_Stop_f (void); +void CL_Record_f (void); +void CL_PlayDemo_f (void); +void CL_PlayDemo_silentfail (void); +void CL_TimeDemo_f (void); + +// +// cl_parse.c +// +void CL_ParseServerMessage (void); +void CL_ParseServerMessageFPM (void); +void CL_NewTranslation (int slot); + +// +// view +// +void V_StartPitchDrift (void); +void V_StopPitchDrift (void); +void V_StopPitchDriftFPM (void); + +void V_RenderView (void); +void V_RenderViewFPM (void); +void V_UpdatePalette (void); +void V_Register (void); +void V_ParseDamage (void); +void V_ParseDamageFPM (void); +void V_SetContentsColor (int contents); +void V_SetContentsColorFPM (int contents); + + +// +// cl_tent +// +void CL_InitTEnts (void); +void CL_SignonReply (void); diff --git a/project/jni/application/quake/source/cmd.c b/project/jni/application/quake/source/cmd.c new file mode 100644 index 000000000..5627b6ec8 --- /dev/null +++ b/project/jni/application/quake/source/cmd.c @@ -0,0 +1,804 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cmd.c -- Quake script command processing module + +#include "quakedef.h" + +void Cmd_ForwardToServer (void); + +#define MAX_ALIAS_NAME 32 + +typedef struct cmdalias_s +{ + struct cmdalias_s *next; + char name[MAX_ALIAS_NAME]; + char *value; +} cmdalias_t; + +cmdalias_t *cmd_alias; + +int trashtest; +int *trashspot; + +qboolean cmd_wait; + + +//============================================================================= + +/* +============ +Cmd_Wait_f + +Causes execution of the remainder of the command buffer to be delayed until +next frame. This allows commands like: +bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2" +============ +*/ +void Cmd_Wait_f (void) +{ + cmd_wait = true; +} + +/* +============================================================================= + + COMMAND BUFFER + +============================================================================= +*/ + +sizebuf_t cmd_text; + +/* +============ +Cbuf_Init +============ +*/ +void Cbuf_Init (void) +{ + SZ_Alloc (&cmd_text, 8192); // space for commands and script files +} + + +/* +============ +Cbuf_AddText + +Adds command text at the end of the buffer +============ +*/ +void Cbuf_AddText (char *text) +{ + int l; + + l = Q_strlen (text); + + if (cmd_text.cursize + l >= cmd_text.maxsize) + { + Con_Printf ("Cbuf_AddText: overflow\n"); + return; + } + + SZ_Write (&cmd_text, text, Q_strlen (text)); +} + + +/* +============ +Cbuf_InsertText + +Adds command text immediately after the current command +Adds a \n to the text +FIXME: actually change the command buffer to do less copying +============ +*/ +void Cbuf_InsertText (char *text) +{ + char *temp; + int templen; + +// copy off any commands still remaining in the exec buffer + templen = cmd_text.cursize; + if (templen) + { + temp = Z_Malloc (templen); + Q_memcpy (temp, cmd_text.data, templen); + SZ_Clear (&cmd_text); + } + else + temp = NULL; // shut up compiler + +// add the entire text of the file + Cbuf_AddText (text); + +// add the copied off data + if (templen) + { + SZ_Write (&cmd_text, temp, templen); + Z_Free (temp); + } +} + +/* +============ +Cbuf_Execute +============ +*/ +void Cbuf_Execute (void) +{ + int i; + char *text; + char line[1024]; + int quotes; + + while (cmd_text.cursize) + { +// find a \n or ; line break + text = (char *)cmd_text.data; + + quotes = 0; + for (i=0 ; i< cmd_text.cursize ; i++) + { + if (text[i] == '"') + quotes++; + if ( !(quotes&1) && text[i] == ';') + break; // don't break if inside a quoted string + if (text[i] == '\n') + break; + } + + + Q_memcpy (line, text, i); + line[i] = 0; + +// delete the text from the command buffer and move remaining commands down +// this is necessary because commands (exec, alias) can insert data at the +// beginning of the text buffer + + if (i == cmd_text.cursize) + cmd_text.cursize = 0; + else + { + i++; + cmd_text.cursize -= i; + Q_memcpy (text, text+i, cmd_text.cursize); + } + +// execute the command line + Cmd_ExecuteString (line, src_command); + + if (cmd_wait) + { // skip out while text still remains in buffer, leaving it + // for next frame + cmd_wait = false; + break; + } + } +} + +/* +============================================================================== + + SCRIPT COMMANDS + +============================================================================== +*/ + +/* +=============== +Cmd_StuffCmds_f + +Adds command line parameters as script statements +Commands lead with a +, and continue until a - or another + +quake +prog jctest.qp +cmd amlev1 +quake -nosound +cmd amlev1 +=============== +*/ +void Cmd_StuffCmds_f (void) +{ + int i, j; + int s; + char *text, *build, c; + + if (Cmd_Argc () != 1) + { + Con_Printf ("stuffcmds : execute command line parameters\n"); + return; + } + +// build the combined string to parse from + s = 0; + for (i=1 ; i : execute a script file\n"); + return; + } + + mark = Hunk_LowMark (); + f = (char *)COM_LoadHunkFile (Cmd_Argv(1)); + if (!f) + { + Con_Printf ("couldn't exec %s\n",Cmd_Argv(1)); + return; + } + Con_Printf ("execing %s\n",Cmd_Argv(1)); + + Cbuf_InsertText (f); + Hunk_FreeToLowMark (mark); +} + + +/* +=============== +Cmd_Echo_f + +Just prints the rest of the line to the console +=============== +*/ +void Cmd_Echo_f (void) +{ + int i; + + for (i=1 ; inext) + Con_Printf ("%s : %s\n", a->name, a->value); + return; + } + + s = Cmd_Argv(1); + if (strlen(s) >= MAX_ALIAS_NAME) + { + Con_Printf ("Alias name is too long\n"); + return; + } + + // if the alias allready exists, reuse it + for (a = cmd_alias ; a ; a=a->next) + { + if (!strcmp(s, a->name)) + { + Z_Free (a->value); + break; + } + } + + if (!a) + { + a = Z_Malloc (sizeof(cmdalias_t)); + a->next = cmd_alias; + cmd_alias = a; + } + strcpy (a->name, s); + +// copy the rest of the command line + cmd[0] = 0; // start out with a null string + c = Cmd_Argc(); + for (i=2 ; i< c ; i++) + { + strcat (cmd, Cmd_Argv(i)); + if (i != c) + strcat (cmd, " "); + } + strcat (cmd, "\n"); + + a->value = CopyString (cmd); +} + +/* +============================================================================= + + COMMAND EXECUTION + +============================================================================= +*/ + +typedef struct cmd_function_s +{ + struct cmd_function_s *next; + char *name; + xcommand_t function; +} cmd_function_t; + + +#define MAX_ARGS 80 + +static int cmd_argc; +static char *cmd_argv[MAX_ARGS]; +static char *cmd_null_string = ""; +static char *cmd_args = NULL; + +cmd_source_t cmd_source; + + +static cmd_function_t *cmd_functions; // possible commands to execute + + +// 2000-01-09 CmdList command by Maddes start + +/* + +======== + +Cmd_List + +======== + +*/ + +void Cmd_List_f (void) + +{ + + cmd_function_t *cmd; + + char *partial; + + int len; + + int count; + + + + if (Cmd_Argc() > 1) + + { + + partial = Cmd_Argv (1); + + len = Q_strlen(partial); + + } + + else + + { + + partial = NULL; + + len = 0; + + } + + + + count=0; + + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + + { + + if (partial && Q_strncmp (partial,cmd->name, len)) + + { + + continue; + + } + + Con_Printf ("\"%s\"\n", cmd->name); + + count++; + + } + + + + Con_Printf ("%i command(s)", count); + + if (partial) + + { + + Con_Printf (" beginning with \"%s\"", partial); + + } + + Con_Printf ("\n"); + +} + +// 2000-01-09 CmdList command by Maddes end + + + +/* +============ +Cmd_Init +============ +*/ +void Cmd_Init (void) +{ +// +// register our commands +// + Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f); + Cmd_AddCommand ("exec",Cmd_Exec_f); + Cmd_AddCommand ("echo",Cmd_Echo_f); + Cmd_AddCommand ("alias",Cmd_Alias_f); + Cmd_AddCommand ("cmd", Cmd_ForwardToServer); + Cmd_AddCommand ("wait", Cmd_Wait_f); + Cmd_AddCommand ("cmdlist", Cmd_List_f); // 2000-01-09 CmdList command by Maddes + Cmd_AddCommand ("cvarlist", Cvar_List_f); // 2000-01-09 CvarList command by Maddes +} + +/* +============ +Cmd_Argc +============ +*/ +int Cmd_Argc (void) +{ + return cmd_argc; +} + +/* +============ +Cmd_Argv +============ +*/ +char *Cmd_Argv (int arg) +{ + if ( (unsigned)arg >= (unsigned)cmd_argc ) + return cmd_null_string; + return cmd_argv[arg]; +} + +/* +============ +Cmd_Args +============ +*/ +char *Cmd_Args (void) +{ + return cmd_args; +} + + +/* +============ +Cmd_TokenizeString + +Parses the given string into command line tokens. +============ +*/ +void Cmd_TokenizeString (char *text) +{ + int i; + +// clear the args from the last string + for (i=0 ; inext) + { + if (!Q_strcmp (cmd_name, cmd->name)) + { + Con_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name); + return; + } + } + + cmd = Hunk_Alloc (sizeof(cmd_function_t)); + cmd->name = cmd_name; + cmd->function = function; + cmd->next = cmd_functions; + cmd_functions = cmd; +} + +/* +============ +Cmd_Exists +============ +*/ +qboolean Cmd_Exists (char *cmd_name) +{ + cmd_function_t *cmd; + + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + { + if (!Q_strcmp (cmd_name,cmd->name)) + return true; + } + + return false; +} + + + +/* +============ +Cmd_CompleteCommand +============ +*/ +char *Cmd_CompleteCommand (char *partial) { + cmd_function_t *cmd; + int len; + cmdalias_t *a; // Added for alias cmd completion + len = Q_strlen(partial); + + if (!len) + return NULL; + +// check functions + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + if (!Q_strncmp (partial,cmd->name, len)) + return cmd->name; + +//The next For loop adds alias cmd completion + for (a=cmd_alias ; a ; a=a->next) + if (!Q_strncmp (partial, a->name, len)) + return a->name; + + return NULL; +} + +/* +============ +Cmd_ExecuteString + +A complete command line has been parsed, so try to execute it +FIXME: lookupnoadd the token to speed search? +============ +*/ +void Cmd_ExecuteString (char *text, cmd_source_t src) +{ + cmd_function_t *cmd; + cmdalias_t *a; + + cmd_source = src; + Cmd_TokenizeString (text); + +// sprintf(gpstr, "cmdexec: %s", text); +// GpError(gpstr,1); + +// execute the command line + if (!Cmd_Argc()) + return; // no tokens + +// check functions + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) + { + if (!Q_strcasecmp (cmd_argv[0],cmd->name)) + { + cmd->function (); + return; + } + } + +// check alias + for (a=cmd_alias ; a ; a=a->next) + { + if (!Q_strcasecmp (cmd_argv[0], a->name)) + { + Cbuf_InsertText (a->value); + return; + } + } + +// check cvars + if (!Cvar_Command ()) + Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0)); + +} + + +/* +=================== +Cmd_ForwardToServer + +Sends the entire command line over to the server +=================== +*/ +void Cmd_ForwardToServer (void) +{ + if (cls.state != ca_connected) + { + Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0)); + return; + } + + if (cls.demoplayback) + return; // not really connected + + MSG_WriteByte (&cls.message, clc_stringcmd); + if (Q_strcasecmp(Cmd_Argv(0), "cmd") != 0) + { + SZ_Print (&cls.message, Cmd_Argv(0)); + SZ_Print (&cls.message, " "); + } + if (Cmd_Argc() > 1) + SZ_Print (&cls.message, Cmd_Args()); + else + SZ_Print (&cls.message, "\n"); +} + + +/* +================ +Cmd_CheckParm + +Returns the position (1 to argc-1) in the command's argument list +where the given parameter apears, or 0 if not present +================ +*/ + +int Cmd_CheckParm (char *parm) +{ + int i; + + if (!parm) + Sys_Error ("Cmd_CheckParm: NULL"); + + for (i = 1; i < Cmd_Argc (); i++) + if (! Q_strcasecmp (parm, Cmd_Argv (i))) + return i; + + return 0; +} diff --git a/project/jni/application/quake/source/cmd.h b/project/jni/application/quake/source/cmd.h new file mode 100644 index 000000000..c4999536d --- /dev/null +++ b/project/jni/application/quake/source/cmd.h @@ -0,0 +1,120 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// cmd.h -- Command buffer and command execution + +//=========================================================================== + +/* + +Any number of commands can be added in a frame, from several different sources. +Most commands come from either keybindings or console line input, but remote +servers can also send across commands and entire text files can be execed. + +The + command line options are also added to the command buffer. + +The game starts with a Cbuf_AddText ("exec quake.rc\n"); Cbuf_Execute (); + +*/ + + +void Cbuf_Init (void); +// allocates an initial text buffer that will grow as needed + +void Cbuf_AddText (char *text); +// as new commands are generated from the console or keybindings, +// the text is added to the end of the command buffer. + +void Cbuf_InsertText (char *text); +// when a command wants to issue other commands immediately, the text is +// inserted at the beginning of the buffer, before any remaining unexecuted +// commands. + +void Cbuf_Execute (void); +// Pulls off \n terminated lines of text from the command buffer and sends +// them through Cmd_ExecuteString. Stops when the buffer is empty. +// Normally called once per frame, but may be explicitly invoked. +// Do not call inside a command function! + +//=========================================================================== + +/* + +Command execution takes a null terminated string, breaks it into tokens, +then searches for a command or variable that matches the first token. + +Commands can come from three sources, but the handler functions may choose +to dissallow the action or forward it to a remote server if the source is +not apropriate. + +*/ + +typedef void (*xcommand_t) (void); + +typedef enum +{ + src_client, // came in over a net connection as a clc_stringcmd + // host_client will be valid during this state. + src_command // from the command buffer +} cmd_source_t; + +extern cmd_source_t cmd_source; + +void Cmd_Init (void); + +void Cmd_AddCommand (char *cmd_name, xcommand_t function); +// called by the init functions of other parts of the program to +// register commands and functions to call for them. +// The cmd_name is referenced later, so it should not be in temp memory + +qboolean Cmd_Exists (char *cmd_name); +// used by the cvar code to check for cvar / command name overlap + +char *Cmd_CompleteCommand (char *partial); +// attempts to match a partial command for automatic command line completion +// returns NULL if nothing fits + +int Cmd_Argc (void); +char *Cmd_Argv (int arg); +char *Cmd_Args (void); +// The functions that execute commands get their parameters with these +// functions. Cmd_Argv () will return an empty string, not a NULL +// if arg > argc, so string operations are allways safe. + +int Cmd_CheckParm (char *parm); +// Returns the position (1 to argc-1) in the command's argument list +// where the given parameter apears, or 0 if not present + +void Cmd_TokenizeString (char *text); +// Takes a null terminated string. Does not need to be /n terminated. +// breaks the string up into arg tokens. + +void Cmd_ExecuteString (char *text, cmd_source_t src); +// Parses a single line of text into arguments and tries to execute it. +// The text can come from the command buffer, a remote client, or stdin. + +void Cmd_ForwardToServer (void); +// adds the current command line as a clc_stringcmd to the client message. +// things like godmode, noclip, etc, are commands directed to the server, +// so when they are typed in at the console, they will need to be forwarded. + +void Cmd_Print (char *text); +// used by command functions to send output to either the graphics console or +// passed as a print message to the client diff --git a/project/jni/application/quake/source/common.c b/project/jni/application/quake/source/common.c new file mode 100644 index 000000000..d48b30a51 --- /dev/null +++ b/project/jni/application/quake/source/common.c @@ -0,0 +1,1879 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// common.c -- misc functions used in client and server + +#include "quakedef.h" + +/* +//Dan +#include "../zlib/zlib.h" +#include +#include //For Compact Flash searching +*/ +#define NUM_SAFE_ARGVS 7 + +static char *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1]; +static char *argvdummy = " "; + +static char *safeargvs[NUM_SAFE_ARGVS] = + {"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-dibonly"}; + +cvar_t registered = {"registered","0"}; +cvar_t cmdline = {"cmdline","0", false, true}; + +qboolean com_modified; // set true if using non-id files + +qboolean proghack; + +int static_registered = 1; // only for startup check, then set + +qboolean msg_suppress_1 = 0; + +void COM_InitFilesystem (void); + +// if a packfile directory differs from this, it is assumed to be hacked +#define PAK0_COUNT 339 +#define PAK0_CRC 32981 + +char com_token[1024]; +int com_argc; +char **com_argv; + +#define CMDLINE_LENGTH 256 +char com_cmdline[CMDLINE_LENGTH]; + +qboolean standard_quake = true, rogue, hipnotic; +/* +// this graphic needs to be in the pak file to use registered features +unsigned short pop[] = +{ + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000 +,0x0000,0x0000,0x6600,0x0000,0x0000,0x0000,0x6600,0x0000 +,0x0000,0x0066,0x0000,0x0000,0x0000,0x0000,0x0067,0x0000 +,0x0000,0x6665,0x0000,0x0000,0x0000,0x0000,0x0065,0x6600 +,0x0063,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6563 +,0x0064,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6564 +,0x0064,0x6564,0x0000,0x6469,0x6969,0x6400,0x0064,0x6564 +,0x0063,0x6568,0x6200,0x0064,0x6864,0x0000,0x6268,0x6563 +,0x0000,0x6567,0x6963,0x0064,0x6764,0x0063,0x6967,0x6500 +,0x0000,0x6266,0x6769,0x6a68,0x6768,0x6a69,0x6766,0x6200 +,0x0000,0x0062,0x6566,0x6666,0x6666,0x6666,0x6562,0x0000 +,0x0000,0x0000,0x0062,0x6364,0x6664,0x6362,0x0000,0x0000 +,0x0000,0x0000,0x0000,0x0062,0x6662,0x0000,0x0000,0x0000 +,0x0000,0x0000,0x0000,0x0061,0x6661,0x0000,0x0000,0x0000 +,0x0000,0x0000,0x0000,0x0000,0x6500,0x0000,0x0000,0x0000 +,0x0000,0x0000,0x0000,0x0000,0x6400,0x0000,0x0000,0x0000 +}; +*/ +/* + + +All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources. + +The "base directory" is the path to the directory holding the quake.exe and all game directories. The sys_* files pass this to host_init in quakeparms_t->basedir. This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory. The base directory is +only used during filesystem initialization. + +The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to. This can be overridden with the "-game" command line parameter. The game directory can never be changed while quake is executing. This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't. + +The "cache directory" is only used during development to save network bandwidth, especially over ISDN / T1 lines. If there is a cache directory +specified, when a file is found by the normal search path, it will be mirrored +into the cache directory, then opened there. + + + +FIXME: +The file "parms.txt" will be read out of the game directory and appended to the current command line arguments to allow different games to initialize startup parms differently. This could be used to add a "-sspeed 22050" for the high quality sound edition. Because they are added at the end, they will not override an explicit setting on the original command line. + +*/ + +//============================================================================ + + +// ClearLink is used for new headnodes +void ClearLink (link_t *l) +{ + l->prev = l->next = l; +} + +void RemoveLink (link_t *l) +{ + l->next->prev = l->prev; + l->prev->next = l->next; +} + +void InsertLinkBefore (link_t *l, link_t *before) +{ + l->next = before; + l->prev = before->prev; + l->prev->next = l; + l->next->prev = l; +} +void InsertLinkAfter (link_t *l, link_t *after) +{ + l->next = after->next; + l->prev = after; + l->prev->next = l; + l->next->prev = l; +} + +/* +============================================================================ + + LIBRARY REPLACEMENT FUNCTIONS + +============================================================================ +*/ + +void Q_memset (void *dest, int fill, int count) +{ + + int i; + + if ( (((long)dest | count) & 3) == 0) + { + count >>= 2; + fill = fill | (fill<<8) | (fill<<16) | (fill<<24); + for (i=0 ; i>=2; + for (i=0 ; i= 'a' && c1 <= 'z') + c1 -= ('a' - 'A'); + if (c2 >= 'a' && c2 <= 'z') + c2 -= ('a' - 'A'); + if (c1 != c2) + return -1; // strings not equal + } + if (!c1) + return 0; // strings are equal +// s1++; +// s2++; + } + + return -1; +} + +int Q_strcasecmp (char *s1, char *s2) +{ + return Q_strncasecmp (s1, s2, 99999); +} + +int Q_atoi (char *str) +{ + int val; + int sign; + int c; + + if (*str == '-') + { + sign = -1; + str++; + } + else + sign = 1; + + val = 0; + +// +// check for hex +// + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) + { + str += 2; + while (1) + { + c = *str++; + if (c >= '0' && c <= '9') + val = (val<<4) + c - '0'; + else if (c >= 'a' && c <= 'f') + val = (val<<4) + c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + val = (val<<4) + c - 'A' + 10; + else + return val*sign; + } + } + +// +// check for character +// + if (str[0] == '\'') + { + return sign * str[1]; + } + +// +// assume decimal +// + while (1) + { + c = *str++; + if (c <'0' || c > '9') + return val*sign; + val = val*10 + c - '0'; + } + + return 0; +} + + +float Q_atof (char *str) +{ + double val; + int sign; + int c; + int decimal, total; + + if (*str == '-') + { + sign = -1; + str++; + } + else + sign = 1; + + val = 0; + +// +// check for hex +// + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') ) + { + str += 2; + while (1) + { + c = *str++; + if (c >= '0' && c <= '9') + val = (val*16) + c - '0'; + else if (c >= 'a' && c <= 'f') + val = (val*16) + c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + val = (val*16) + c - 'A' + 10; + else + return (float)(val*sign); + } + } + +// +// check for character +// + if (str[0] == '\'') + { + return (float)(sign * str[1]); + } + +// +// assume decimal +// + decimal = -1; + total = 0; + while (1) + { + c = *str++; + if (c == '.') + { + decimal = total; + continue; + } + if (c <'0' || c > '9') + break; + val = val*10 + c - '0'; + total++; + } + + if (decimal == -1) + return (float)(val*sign); + while (total > decimal) + { + val /= 10; + total--; + } + + return (float)(val*sign); +} + +void Q_strncpyz (char *dest, char *src, size_t size) { + strncpy (dest, src, size - 1); + dest[size-1] = 0; +} + +/* +============================================================================ + BYTE ORDER FUNCTIONS +============================================================================ +*/ + +qboolean bigendien; + +short (*BigShort) (short l); +short (*LittleShort) (short l); +int (*BigLong) (int l); +int (*LittleLong) (int l); +float (*BigFloat) (float l); +float (*LittleFloat) (float l); + +short ShortSwap (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short ShortNoSwap (short l) +{ + return l; +} + +int LongSwap (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int LongNoSwap (int l) +{ + return l; +} + +float FloatSwap (float f) +{ + union + { + float f; + byte b[4]; + } dat1, dat2; + + + dat1.f = f; + dat2.b[0] = dat1.b[3]; + dat2.b[1] = dat1.b[2]; + dat2.b[2] = dat1.b[1]; + dat2.b[3] = dat1.b[0]; + return dat2.f; +} + +float FloatNoSwap (float f) +{ + return f; +} + +/* +============================================================================== + + MESSAGE IO FUNCTIONS + +Handles byte ordering and avoids alignment errors +============================================================================== +*/ + +// +// writing functions +// + +void MSG_WriteChar (sizebuf_t *sb, int c) +{ + byte *buf; + +#ifdef PARANOID + if (c < -128 || c > 127) + Sys_Error ("MSG_WriteChar: range error"); +#endif + + buf = SZ_GetSpace (sb, 1); + buf[0] = c; +} + +void MSG_WriteByte (sizebuf_t *sb, int c) +{ + byte *buf; + +#ifdef PARANOID + if (c < 0 || c > 255) + Sys_Error ("MSG_WriteByte: range error"); +#endif + + buf = SZ_GetSpace (sb, 1); + buf[0] = c; +} + +void MSG_WriteShort (sizebuf_t *sb, int c) +{ + byte *buf; + +#ifdef PARANOID + if (c < ((short)0x8000) || c > (short)0x7fff) + Sys_Error ("MSG_WriteShort: range error"); +#endif + + buf = SZ_GetSpace (sb, 2); + buf[0] = c&0xff; + buf[1] = c>>8; +} + +void MSG_WriteLong (sizebuf_t *sb, int c) +{ + byte *buf; + + buf = SZ_GetSpace (sb, 4); + buf[0] = c&0xff; + buf[1] = (c>>8)&0xff; + buf[2] = (c>>16)&0xff; + buf[3] = c>>24; +} + +void MSG_WriteFloat (sizebuf_t *sb, float f) +{ + union + { + float f; + int l; + } dat; + + + dat.f = f; + dat.l = LittleLong (dat.l); + + SZ_Write (sb, &dat.l, 4); +} + +void MSG_WriteString (sizebuf_t *sb, char *s) +{ + if (!s) + SZ_Write (sb, "", 1); + else + SZ_Write (sb, s, Q_strlen(s)+1); +} + +void MSG_WriteCoord (sizebuf_t *sb, float f) +{ + MSG_WriteShort (sb, (int)(f*8)); +} + +#ifdef USEFPM +void MSG_WriteCoordFPM (sizebuf_t *sb, fixedpoint_t f) +{ + MSG_WriteShort (sb, (int)(FPM_TOFLOAT(f)*8)); +} +#endif + +void MSG_WriteAngle (sizebuf_t *sb, float f) +{ + MSG_WriteByte (sb, ((int)f*256/360) & 255); +} +#ifdef USEFPM +void MSG_WriteAngleFPM (sizebuf_t *sb, fixedpoint_t f) +{ + MSG_WriteByte (sb, ((int)FPM_TOFLOAT(f)*256/360) & 255); +} +#endif +// +// reading functions +// +int msg_readcount; +qboolean msg_badread; + +void MSG_BeginReading (void) +{ + msg_readcount = 0; + msg_badread = false; +} + +// returns -1 and sets msg_badread if no more characters are available +int MSG_ReadChar (void) +{ + int c; + + if (msg_readcount+1 > net_message.cursize) + { + msg_badread = true; + return -1; + } + + c = (signed char)net_message.data[msg_readcount]; + msg_readcount++; + + return c; +} + +int MSG_ReadByte (void) +{ + int c; + + if (msg_readcount+1 > net_message.cursize) + { + msg_badread = true; + return -1; + } + + c = (unsigned char)net_message.data[msg_readcount]; + msg_readcount++; + + return c; +} + +int MSG_ReadShort (void) +{ + int c; + + if (msg_readcount+2 > net_message.cursize) + { + msg_badread = true; + return -1; + } + + c = (short)(net_message.data[msg_readcount] + + (net_message.data[msg_readcount+1]<<8)); + + msg_readcount += 2; + + return c; +} + +int MSG_ReadLong (void) +{ + int c; + + if (msg_readcount+4 > net_message.cursize) + { + msg_badread = true; + return -1; + } + + c = net_message.data[msg_readcount] + + (net_message.data[msg_readcount+1]<<8) + + (net_message.data[msg_readcount+2]<<16) + + (net_message.data[msg_readcount+3]<<24); + + msg_readcount += 4; + + return c; +} + +float MSG_ReadFloat (void) +{ + union + { + byte b[4]; + float f; + int l; + } dat; + + dat.b[0] = net_message.data[msg_readcount]; + dat.b[1] = net_message.data[msg_readcount+1]; + dat.b[2] = net_message.data[msg_readcount+2]; + dat.b[3] = net_message.data[msg_readcount+3]; + msg_readcount += 4; + + dat.l = LittleLong (dat.l); + + return dat.f; +} + +char *MSG_ReadString (void) +{ + static char string[2048]; + int l,c; + + l = 0; + do + { + c = MSG_ReadChar (); + if (c == -1 || c == 0) + break; + string[l] = c; + l++; + } while (l < sizeof(string)-1); + + string[l] = 0; + + return string; +} + +float MSG_ReadCoord (void) +{ + return (float)(MSG_ReadShort() * (1.0/8)); +} + +float MSG_ReadAngle (void) +{ + return (float)(MSG_ReadChar() * (360.0/256)); +} + + + +//=========================================================================== + +void SZ_Alloc (sizebuf_t *buf, int startsize) +{ + if (startsize < 256) + startsize = 256; + buf->data = Hunk_AllocName (startsize, "sizebuf"); + buf->maxsize = startsize; + buf->cursize = 0; +} + + +void SZ_Free (sizebuf_t *buf) +{ +// Z_Free (buf->data); +// buf->data = NULL; +// buf->maxsize = 0; + buf->cursize = 0; +} + +void SZ_Clear (sizebuf_t *buf) +{ + buf->cursize = 0; +} + +void *SZ_GetSpace (sizebuf_t *buf, int length) +{ + void *data; + + if (buf->cursize + length > buf->maxsize) + { + if (!buf->allowoverflow) + Sys_Error ("SZ_GetSpace: overflow without allowoverflow set"); + + if (length > buf->maxsize) + Sys_Error ("SZ_GetSpace: %i is > full buffer size", length); + + buf->overflowed = true; + Con_Printf ("SZ_GetSpace: overflow"); + SZ_Clear (buf); + } + + data = buf->data + buf->cursize; + buf->cursize += length; + + return data; +} + +void SZ_Write (sizebuf_t *buf, void *data, int length) +{ + Q_memcpy (SZ_GetSpace(buf,length),data,length); +} + +void SZ_Print (sizebuf_t *buf, char *data) +{ + int len; + + len = Q_strlen(data)+1; + +// byte * cast to keep VC++ happy + if (buf->data[buf->cursize-1]) + Q_memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0 + else + Q_memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0 +} + + +//============================================================================ + + +/* +============ +COM_SkipPath +============ +*/ +char *COM_SkipPath (char *pathname) +{ + char *last; + + last = pathname; + while (*pathname) + { + if (*pathname=='/') + last = pathname+1; + pathname++; + } + return last; +} + +/* +============ +COM_StripExtension +============ +*/ +void COM_StripExtension (char *in, char *out) +{ + while (*in && *in != '.') + *out++ = *in++; + *out = 0; +} + +/* +============ +COM_FileExtension +============ +*/ +char *COM_FileExtension (char *in) +{ + static char exten[8]; + int i; + + while (*in && *in != '.') + in++; + if (!*in) + return ""; + in++; + for (i=0 ; i<7 && *in ; i++,in++) + exten[i] = *in; + exten[i] = 0; + return exten; +} + +/* +============ +COM_FileBase +============ +*/ +void COM_FileBase (char *in, char *out) +{ + char *s, *s2; + + s = in + strlen(in) - 1; + + while (s != in && *s != '.') + s--; + + for (s2 = s ; *s2 && *s2 != '/' ; s2--) + ; + + if (s-s2 < 2) + strcpy (out,"?model?"); + else + { + s--; + strncpy (out,s2+1, s-s2); + out[s-s2] = 0; + } +} + + +/* +================== +COM_DefaultExtension +================== +*/ +void COM_DefaultExtension (char *path, char *extension) +{ + char *src; +// +// if path doesn't have a .EXT, append extension +// (extension should include the .) +// + src = path + strlen(path) - 1; + + while (*src != '/' && src != path) + { + if (*src == '.') + return; // it has an extension + src--; + } + + strcat (path, extension); +} + + +/* +============== +COM_Parse + +Parse a token out of a string +============== +*/ +char *COM_Parse (char *data) +{ + int c; + int len; + + len = 0; + com_token[0] = 0; + + if (!data) + return NULL; + +// skip whitespace +skipwhite: + while ( (c = *data) <= ' ') + { + if (c == 0) + return NULL; // end of file; + data++; + } + +// skip // comments + if (c=='/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; + } + + +// handle quoted strings specially + if (c == '\"') + { + data++; + while (1) + { + c = *data++; + if (c=='\"' || !c) + { + com_token[len] = 0; + return data; + } + com_token[len] = c; + len++; + } + } + +// parse single characters + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + { + com_token[len] = c; + len++; + com_token[len] = 0; + return data+1; + } + +// parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + break; + } while (c>32); + + com_token[len] = 0; + return data; +} + + +/* +================ +COM_CheckParm + +Returns the position (1 to argc-1) in the program's argument list +where the given parameter apears, or 0 if not present +================ +*/ +int COM_CheckParm (char *parm) +{ + int i; + + for (i=1 ; inext) { + if (s->pack) { + Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles); + } + else + Con_Printf ("%s\n", s->filename); + } +} + +/* +============ +COM_WriteFile + +The filename will be prefixed by the current game directory +============ +*/ +void COM_WriteFile (char *filename, void *data, int len) +{ + int handle; + char name[MAX_OSPATH]; + + sprintf (name, "%s/%s", com_gamedir, filename); + + handle = Sys_FileOpenWrite (name); + if (handle == -1) + { + Sys_Printf ("COM_WriteFile: failed on %s\n", name); + return; + } + + Sys_Printf ("COM_WriteFile: %s\n", name); + Sys_FileWrite (handle, data, len); + Sys_FileClose (handle); + sync(); + +} + + +/* +============ +COM_CreatePath + +Only used for CopyFile +============ +*/ +void COM_CreatePath (char *path) +{ + char *ofs; + + for (ofs = path+1 ; *ofs ; ofs++) + { + if (*ofs == '/') + { // create the directory + *ofs = 0; + Sys_mkdir (path); + *ofs = '/'; + } + } +} + + +/* +=========== +COM_CopyFile + +Copies a file over from the net to the local cache, creating any directories +needed. This is for the convenience of developers using ISDN from home. +=========== +*/ +void COM_CopyFile (char *netpath, char *cachepath) +{ + int in, out; + int remaining, count; + char buf[4096]; + + remaining = Sys_FileOpenRead (netpath, &in); + COM_CreatePath (cachepath); // create directories up to the cache file + out = Sys_FileOpenWrite (cachepath); + + while (remaining) + { + if (remaining < sizeof(buf)) + count = remaining; + else + count = sizeof(buf); + Sys_FileRead (in, buf, count); + Sys_FileWrite (out, buf, count); + remaining -= count; + } + + Sys_FileClose (in); + Sys_FileClose (out); + sync(); +} + +/* +=========== +COM_FindFile + +Finds the file in the search path. +Sets com_filesize and one of handle or file +=========== +*/ + +int COM_FindFile (char *filename, int *handle, FILE **file) +{ + searchpath_t *search; + char netpath[MAX_OSPATH]; + char cachepath[MAX_OSPATH]; + pack_t *pak; + int i; + int findtime, cachetime; + + if (file && handle) + Sys_Error ("COM_FindFile: both handle and file set"); + if (!file && !handle) + Sys_Error ("COM_FindFile: neither handle or file set"); + +// +// search through the path, one element at a time +// + search = com_searchpaths; + if (proghack) + { // gross hack to use quake 1 progs with quake 2 maps + if (!Q_strcmp(filename, "progs.dat")) + search = search->next; + } + + for ( ; search ; search = search->next) + { + // is the element a pak file? + if (search->pack) + { + // look through all the pak file elements + pak = search->pack; + for (i=0 ; inumfiles ; i++) + if (!Q_strcmp (pak->files[i].name, filename)) + { // found it! + // Sys_Printf ("PackFile: %s : %s\n",pak->filename, filename); + if (handle) + { + *handle = pak->handle; + Sys_FileSeek (pak->handle, pak->files[i].filepos); + } + else + { // open a new file on the pakfile + //Dan: Compression added + // (gzFile)(*file)=gzopen(pak->filename, "rb"); + // if (*file) gzseek((gzFile)*file, pak->files[i].filepos, SEEK_SET); + *file = fopen (pak->filename, "rb"); + if (*file) + fseek (*file, pak->files[i].filepos, SEEK_SET); + } + com_filesize = pak->files[i].filelen; + return com_filesize; + } + } + else + { + // check a file in the directory tree + if (!static_registered) + { // if not a registered version, don't ever go beyond base + if ( strchr (filename, '/') || strchr (filename,'\\')) + continue; + } + + sprintf (netpath, "%s/%s",search->filename, filename); + + findtime = Sys_FileTime (netpath); + if (findtime == -1) + continue; + #if 0 + // see if the file needs to be updated in the cache + if (!com_cachedir[0]) + strcpy (cachepath, netpath); + else + { +#if defined(_WIN32) + if ((strlen(netpath) < 2) || (netpath[1] != ':')) + sprintf (cachepath,"%s%s", com_cachedir, netpath); + else + sprintf (cachepath,"%s%s", com_cachedir, netpath+2); +#else + sprintf (cachepath,"%s%s", com_cachedir, netpath); +#endif + + cachetime = Sys_FileTime (cachepath); + + if (cachetime < findtime) + COM_CopyFile (netpath, cachepath); + strcpy (netpath, cachepath); + } +#endif + Sys_Printf ("FindFile: %s\n",netpath); + com_filesize = Sys_FileOpenRead (netpath, &i); + if (handle) + *handle = i; + else + { + Sys_FileClose (i); + *file = fopen (netpath, "rb"); + } + return com_filesize; + } + + } + + Sys_Printf ("FindFile: can't find %s\n", filename); + + if (handle) + *handle = -1; + else + *file = NULL; + com_filesize = -1; + return -1; +} + + +/* +=========== +COM_OpenFile + +filename never has a leading slash, but may contain directory walks +returns a handle and a length +it may actually be inside a pak file +=========== +*/ +int COM_OpenFile (char *filename, int *handle) +{ + return COM_FindFile (filename, handle, NULL); +} + +/* +=========== +COM_FOpenFile + +If the requested file is inside a packfile, a new FILE * will be opened +into the file. +=========== +*/ +int COM_FOpenFile (char *filename, FILE **file) +{ + return COM_FindFile (filename, NULL, file); +} + +/* +============ +COM_CloseFile + +If it is a pak file handle, don't really close it +============ +*/ +void COM_CloseFile (int h) +{ + searchpath_t *s; + + for (s = com_searchpaths ; s ; s=s->next) + if (s->pack && s->pack->handle == h) + return; + + Sys_FileClose (h); +} + + +/* +============ +COM_LoadFile + +Filename are reletive to the quake directory. +Allways appends a 0 byte. +============ +*/ +cache_user_t *loadcache; +byte *loadbuf; +int loadsize; +//char base[32]; + +byte *COM_LoadFile (char *path, int usehunk) +{ + int h; + byte *buf; + char base[32]; + int len; + + buf = NULL; // quiet compiler warning + +// look for it in the filesystem or pack files + + len = COM_OpenFile (path, &h); + if (h == -1 ) { + return NULL; + } + +// extract the filename base name for hunk tag + COM_FileBase (path, base); + + if (usehunk == 1) + buf = Hunk_AllocName (len+1, base); + else if (usehunk == 2) + buf = Hunk_TempAlloc (len+1); + else if (usehunk == 0) + buf = Z_Malloc (len+1); + else if (usehunk == 3) + buf = Cache_Alloc (loadcache, len+1, base); + else if (usehunk == 4) + { + if (len+1 > loadsize) + buf = Hunk_TempAlloc (len+1); + else + buf = loadbuf; + } + else + Sys_Error ("COM_LoadFile: bad usehunk"); + + if (!buf) + Sys_Error ("COM_LoadFile: not enough space for %s", path); + + ((byte *)buf)[len] = 0; + + Draw_BeginDisc (); + Sys_FileRead (h, buf, len); + COM_CloseFile (h); + Draw_EndDisc (); + + return buf; +} + +byte *COM_LoadHunkFile (char *path) +{ + return COM_LoadFile (path, 1); +} + +byte *COM_LoadTempFile (char *path) +{ + return COM_LoadFile (path, 2); +} + +void COM_LoadCacheFile (char *path, struct cache_user_s *cu) +{ + loadcache = cu; + COM_LoadFile (path, 3); +} + +// uses temp hunk if larger than bufsize +byte *COM_LoadStackFile (char *path, void *buffer, int bufsize) +{ + byte *buf; + + loadbuf = (byte *)buffer; + loadsize = bufsize; + buf = COM_LoadFile (path, 4); + + return buf; +} + +/* +================= +COM_LoadPackFile + +Takes an explicit (not game tree related) path to a pak file. + +Loads the header and directory, adding the files at the beginning +of the list so they override previous pack files. +================= +*/ +pack_t *COM_LoadPackFile (char *packfile) { + dpackheader_t header; + int i; + packfile_t *newfiles; + int numpackfiles; + pack_t *pack; + int packhandle; + dpackfile_t info[MAX_FILES_IN_PACK]; + unsigned short crc; + + if (Sys_FileOpenRead (packfile, &packhandle) == -1) + { + Con_Printf ("Couldn't open %s\n", packfile); + return NULL; + } + Sys_FileRead (packhandle, (void *)&header, sizeof(header)); + if (header.id[0] != 'P' || header.id[1] != 'A' + || header.id[2] != 'C' || header.id[3] != 'K') + Sys_Error ("%s is not a packfile", packfile); + header.dirofs = LittleLong (header.dirofs); + header.dirlen = LittleLong (header.dirlen); + + numpackfiles = header.dirlen / sizeof(dpackfile_t); + + if (numpackfiles > MAX_FILES_IN_PACK) + Sys_Error ("%s has %i files", packfile, numpackfiles); + + if (numpackfiles != PAK0_COUNT) + com_modified = true; // not the original file + + newfiles = Hunk_AllocName (numpackfiles * sizeof(packfile_t), "packfile"); + +// info=malloc(sizeof(dpackfile_t)*MAX_FILES_IN_PACK); + + Sys_FileSeek (packhandle, header.dirofs); + Sys_FileRead (packhandle, (void *)info, header.dirlen); + +// crc the directory to check for modifications + CRC_Init (&crc); + for (i=0 ; ifilename, packfile); + pack->handle = packhandle; + pack->numfiles = numpackfiles; + pack->files = newfiles; + + + Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles); + return pack; +} + + +/* +================ +COM_AddGameDirectory + +Sets com_gamedir, adds the directory to the head of the path, +then loads and adds pak1.pak pak2.pak ... +================ +*/ +int COM_AddGameDirectory (char *dir) +{ + int i; + searchpath_t *search; + pack_t *pak; + char pakfile[MAX_OSPATH]; + int success=0; + int loadpak = 0; + + Q_strcpy (com_gamedir, dir); + +// +// add the directory to the search path +// + search = Hunk_Alloc (sizeof(searchpath_t)); + Q_strcpy (search->filename, dir); + search->next = com_searchpaths; + com_searchpaths = search; + +// +// add any pak files in the format pak0.pak pak1.pak, ... +// + for (i = 0; ;i++) { + sprintf (pakfile, "%s/pak%i.pak", dir, i); + pak = COM_LoadPackFile (pakfile); + + if (!pak) { + break; + } else { + success = 1; + } + + search = Hunk_Alloc (sizeof(searchpath_t)); + search->pack = pak; + search->next = com_searchpaths; + com_searchpaths = search; + } + + // R2-Tec load PAK. + sprintf (pakfile, "q_sys/r2-tec.pak"); + pak = COM_LoadPackFile (pakfile); + + search = Hunk_Alloc (sizeof(searchpath_t)); + search->pack = pak; + search->next = com_searchpaths; + com_searchpaths = search; + +// +// add the contents of the parms.txt file to the end of the command line +// + return success; +} + +/* +================ +COM_InitFilesystem +================ +*/ +void COM_InitFilesystem (void) +{ + int i, j; + char basedir[MAX_OSPATH]; + searchpath_t *search; + char allSearchDirs[10][MAX_OSPATH]; + int allSearchDirsCount=0; + int loop; + +// +// -basedir +// Overrides the system supplied base directory (under GAMENAME) + +//Dan East: Added support for searching multiple directories for wad files. +//Directory names are placed in the allSearchDirs array, with allSearchDirsCount +//set to indicate the number of valid entries + + i = COM_CheckParm ("-basedir"); + if (i && i < com_argc-1) + strcpy (basedir, com_argv[i+1]); + else + strcpy (basedir, host_parms.basedir); + + j = strlen (basedir); + + if (j > 0) + { + if ((basedir[j-1] == '\\') || (basedir[j-1] == '/')) + basedir[j-1] = 0; + } + + +// +// -cachedir +// Overrides the system supplied cache directory (NULL or /qcache) +// -cachedir - will disable caching. +// + i = COM_CheckParm ("-cachedir"); + if (i && i < com_argc-1) + { + if (com_argv[i+1][0] == '-') + com_cachedir[0] = 0; + else + strcpy (com_cachedir, com_argv[i+1]); + } + else if (host_parms.cachedir) + strcpy (com_cachedir, host_parms.cachedir); + else + com_cachedir[0] = 0; + +// +// start up with GAMENAME by default (id1) +// + if (r2_mod == 0) { + COM_AddGameDirectory (va("%s/id1", basedir) ); + } else if (r2_mod == 1) { + COM_AddGameDirectory (va("%s/hipnotic", basedir) ); + } else if (r2_mod == 2) { + COM_AddGameDirectory (va("%s/rogue", basedir) ); + } + + /* if (COM_CheckParm ("-rogue")) + COM_AddGameDirectory (va("%s/rogue", basedir) ); + if (COM_CheckParm ("-hipnotic")) + COM_AddGameDirectory (va("%s/hipnotic", basedir) ); */ + +// +// -game +// Adds basedir/gamedir as an override game +// + i = COM_CheckParm ("-game"); + if (i && i < com_argc-1) + { + com_modified = true; + COM_AddGameDirectory (va("%s/%s", basedir, com_argv[i+1])); + } + +// +// -path [] ... +// Fully specifies the exact serach path, overriding the generated one +// + i = COM_CheckParm ("-path"); + if (i) + { + com_modified = true; + com_searchpaths = NULL; + while (++i < com_argc) + { + if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-') + break; + + search = Hunk_Alloc (sizeof(searchpath_t)); + if ( !strcmp(COM_FileExtension(com_argv[i]), "pak") ) + { + search->pack = COM_LoadPackFile (com_argv[i]); + if (!search->pack) + Sys_Error ("Couldn't load packfile: %s", com_argv[i]); + } + else + strcpy (search->filename, com_argv[i]); + search->next = com_searchpaths; + com_searchpaths = search; + } + } + + if (COM_CheckParm ("-proghack")) + proghack = true; +} + + diff --git a/project/jni/application/quake/source/common.h b/project/jni/application/quake/source/common.h new file mode 100644 index 000000000..a0bd2540c --- /dev/null +++ b/project/jni/application/quake/source/common.h @@ -0,0 +1,198 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// comndef.h -- general definitions + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +//#include "zlib.h" + +//#ifndef BYTE_DEFINED +typedef unsigned char byte; +//#define BYTE_DEFINED 1 +//#endif + +#undef true +#undef false + +typedef enum {false, true} qboolean; + +int doublesize; + +//============================================================================ + +typedef struct sizebuf_s +{ + qboolean allowoverflow; // if false, do a Sys_Error + qboolean overflowed; // set to true if the buffer size failed + byte *data; + int maxsize; + int cursize; +} sizebuf_t; + +void SZ_Alloc (sizebuf_t *buf, int startsize); +void SZ_Free (sizebuf_t *buf); +void SZ_Clear (sizebuf_t *buf); +void *SZ_GetSpace (sizebuf_t *buf, int length); +void SZ_Write (sizebuf_t *buf, void *data, int length); +void SZ_Print (sizebuf_t *buf, char *data); // strcats onto the sizebuf + +//============================================================================ + +typedef struct link_s +{ + struct link_s *prev, *next; +} link_t; + + +void ClearLink (link_t *l); +void RemoveLink (link_t *l); +void InsertLinkBefore (link_t *l, link_t *before); +void InsertLinkAfter (link_t *l, link_t *after); + +// (type *)STRUCT_FROM_LINK(link_t *link, type, member) +// ent = STRUCT_FROM_LINK(link,entity_t,order) +// FIXME: remove this mess! +#define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (int)&(((t *)0)->m))) + +//============================================================================ + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define Q_MAXCHAR ((char)0x7f) +#define Q_MAXSHORT ((short)0x7fff) +#define Q_MAXINT ((int)0x7fffffff) +#define Q_MAXLONG ((int)0x7fffffff) +#define Q_MAXFLOAT ((int)0x7fffffff) + +#define Q_MINCHAR ((char)0x80) +#define Q_MINSHORT ((short)0x8000) +#define Q_MININT ((int)0x80000000) +#define Q_MINLONG ((int)0x80000000) +#define Q_MINFLOAT ((int)0x7fffffff) + +//============================================================================ + +extern qboolean bigendien; + +extern short (*BigShort) (short l); +extern short (*LittleShort) (short l); +extern int (*BigLong) (int l); +extern int (*LittleLong) (int l); +extern float (*BigFloat) (float l); +extern float (*LittleFloat) (float l); + +//============================================================================ + +void MSG_WriteChar (sizebuf_t *sb, int c); +void MSG_WriteByte (sizebuf_t *sb, int c); +void MSG_WriteShort (sizebuf_t *sb, int c); +void MSG_WriteLong (sizebuf_t *sb, int c); +void MSG_WriteFloat (sizebuf_t *sb, float f); +void MSG_WriteString (sizebuf_t *sb, char *s); +void MSG_WriteCoord (sizebuf_t *sb, float f); +//void MSG_WriteCoordFPM (sizebuf_t *sb, fixedpoint_t f); +void MSG_WriteAngle (sizebuf_t *sb, float f); +//void MSG_WriteAngleFPM (sizebuf_t *sb, fixedpoint_t f); + +extern int msg_readcount; +extern qboolean msg_badread; // set if a read goes beyond end of message + +void MSG_BeginReading (void); +int MSG_ReadChar (void); +int MSG_ReadByte (void); +int MSG_ReadShort (void); +int MSG_ReadLong (void); +float MSG_ReadFloat (void); +char *MSG_ReadString (void); + +float MSG_ReadCoord (void); +float MSG_ReadAngle (void); + +//============================================================================ + +void Q_memset (void *dest, int fill, int count); +/*__inline*/ // inline static void Q_memcpy (void *dest, void *src, int count) {gm_memcpy(dest, src, count);}; +void Q_memcpy (void *dest, void *src, int count); +int Q_memcmp (void *m1, void *m2, int count); +void Q_strcpy (char *dest, char *src); +void Q_strncpy (char *dest, char *src, int count); +int Q_strlen (char *str); +char *Q_strrchr (char *s, char c); +void Q_strcat (char *dest, char *src); +int Q_strcmp (char *s1, char *s2); +int Q_strncmp (char *s1, char *s2, int count); +int Q_strcasecmp (char *s1, char *s2); +int Q_strncasecmp (char *s1, char *s2, int n); +int Q_atoi (char *str); +float Q_atof (char *str); +void Q_strncpyz (char *dest, char *src, size_t size); + +//============================================================================ + +extern char com_token[1024]; +extern qboolean com_eof; + +char *COM_Parse (char *data); + + +extern int com_argc; +extern char **com_argv; + +int COM_CheckParm (char *parm); +void COM_Init (char *path); +void COM_InitArgv (int argc, char **argv); + +char *COM_SkipPath (char *pathname); +void COM_StripExtension (char *in, char *out); +void COM_FileBase (char *in, char *out); +void COM_DefaultExtension (char *path, char *extension); + +char *va(char *format, ...); +// does a varargs printf into a temp buffer + + +//============================================================================ + +extern int com_filesize; +struct cache_user_s; + +extern char com_gamedir[MAX_OSPATH]; + +void COM_WriteFile (char *filename, void *data, int len); +int COM_OpenFile (char *filename, int *hndl); +int COM_FOpenFile (char *filename, FILE **file); +void COM_CloseFile (int h); + +byte *COM_LoadStackFile (char *path, void *buffer, int bufsize); +byte *COM_LoadTempFile (char *path); +byte *COM_LoadHunkFile (char *path); +void COM_LoadCacheFile (char *path, struct cache_user_s *cu); + + +extern struct cvar_s registered; + +extern qboolean standard_quake, rogue, hipnotic; + + + +#endif // _COMMON_H_ diff --git a/project/jni/application/quake/source/console.c b/project/jni/application/quake/source/console.c new file mode 100644 index 000000000..3d9be6db1 --- /dev/null +++ b/project/jni/application/quake/source/console.c @@ -0,0 +1,641 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// console.c + +#ifdef NeXT +#include +#endif +#ifndef _MSC_VER +#include +#endif + +//#include + +#include "quakedef.h" + +extern int min_vid_width; + +int con_linewidth; +float con_cursorspeed = 4; +#define CON_TEXTSIZE 16384 + +qboolean con_forcedup; // because no entities to refresh + +int con_totallines; // total lines in console scrollback +int con_backscroll; // lines up from bottom to display +int con_current; // where next message will be printed +int con_x; // offset in current line for next print +char *con_text=0; + +cvar_t con_notifytime = {"con_notifytime","3"}; //seconds + +#define NUM_CON_TIMES 4 +float con_times[NUM_CON_TIMES]; // realtime time the line was generated + // for transparent notify lines + +int con_vislines; + +qboolean con_debuglog; + +#define MAXCMDLINE 256 +extern char key_lines[32][MAXCMDLINE]; +extern int edit_line; +extern int key_linepos; + + +qboolean con_initialized; + +int con_notifylines; // scan lines to clear for notify lines + +extern void M_Menu_Main_f (void); + + +/* +================ +Con_ToggleConsole_f +================ +*/ +void Con_ToggleConsole_f (void) { + if (key_dest == key_console) { + if (cls.state == ca_connected) { + key_dest = key_game; + key_lines[edit_line][1] = 0; + key_linepos = 1; + } else { + M_Menu_Main_f (); + } + } else { + key_dest = key_console; + } + + SCR_EndLoadingPlaque (); + Q_memset (con_times, 0, sizeof(con_times)); +} + +/* +================ +Con_Clear_f +================ +*/ +void Con_Clear_f (void) { + if (con_text) + Q_memset (con_text, ' ', CON_TEXTSIZE); +} + +/* +================ +Con_ClearNotify +================ +*/ +void Con_ClearNotify (void) { + int i; + + for (i=0 ; i> 3) - 2; + + if (width == con_linewidth) + return; + + if (width < 1) // video hasn't been initialized yet + { + width = 38; + con_linewidth = width; + con_totallines = CON_TEXTSIZE / con_linewidth; + Q_memset (con_text, ' ', CON_TEXTSIZE); + } + else + { + oldwidth = con_linewidth; + con_linewidth = width; + oldtotallines = con_totallines; + con_totallines = CON_TEXTSIZE / con_linewidth; + numlines = oldtotallines; + + if (con_totallines < numlines) + numlines = con_totallines; + + numchars = oldwidth; + + if (con_linewidth < numchars) + numchars = con_linewidth; + + Q_memcpy (tbuf, con_text, CON_TEXTSIZE); + Q_memset (con_text, ' ', CON_TEXTSIZE); + + for (i=0 ; i con_linewidth) ) + con_x = 0; + + txt++; + + if (cr) + { + con_current--; + cr = false; + } + + + if (!con_x) + { + Con_Linefeed (); + // mark time for transparent overlay + if (con_current >= 0) + con_times[con_current % NUM_CON_TIMES] = realtime; + } + + switch (c) + { + case '\n': + con_x = 0; + break; + + case '\r': + con_x = 0; + cr = 1; + break; + + default: // display character and advance + y = con_current % con_totallines; + con_text[y*con_linewidth+con_x] = c | mask; + con_x++; + if (con_x >= con_linewidth) + con_x = 0; + break; + } + + } +} + + +/* +================ +Con_DebugLog +================ +*/ +void Con_DebugLog(char *file, char *fmt, ...) +{ + va_list argptr; + static char data[1024]; + FILE *fd; + long old; + /* + va_start(argptr, fmt); + vsprintf(data, fmt, argptr); + va_end(argptr); + + fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666); + write(fd, data, strlen(data)); + close(fd); + */ +} + + +/* +================ +Con_Printf + +Handles cursor positioning, line wrapping, etc +================ +*/ +#define MAXPRINTMSG 4096 +// FIXME: make a buffer size safe vsprintf? +void Con_Printf (char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + static qboolean inupdate; + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + +// also echo to debugging console + Sys_Printf ("%s", msg); // also echo to debugging console + +// log all messages to file + if (con_debuglog) + Con_DebugLog(va("%s\\qconsole.log",com_gamedir), "%s", msg); + + if (!con_initialized) + return; + + if (cls.state == ca_dedicated) + return; // no graphics mode + +// write it to the scrollable buffer + Con_Print (msg); + +// update the screen if the console is displayed + if (cls.signon != SIGNONS && !scr_disabled_for_loading ) + { + // protect against infinite loop if something in SCR_UpdateScreen calls + // Con_Printd + if (!inupdate) + { + inupdate = true; + SCR_UpdateScreen (); + inupdate = false; + } + } +} + +/* +================ +Con_DPrintf + +A Con_Printf that only shows up if the "developer" cvar is set +================ +*/ +void Con_DPrintf (char *fmt, ...) +{ + va_list argptr; + char msg[MAXPRINTMSG]; + + if (!developer.value) + return; // don't confuse non-developers with techie stuff... + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + Con_Printf ("%s", msg); +} + + +/* +================== +Con_SafePrintf + +Okay to call even when the screen can't be updated +================== +*/ +void Con_SafePrintf (char *fmt, ...) +{ + va_list argptr; + char msg[1024]; + int temp; + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + temp = scr_disabled_for_loading; + scr_disabled_for_loading = true; + Con_Printf ("%s", msg); + scr_disabled_for_loading = temp; +} + + +/* +============================================================================== + +DRAWING + +============================================================================== +*/ + + +/* +================ +Con_DrawInput + +The input line scrolls horizontally if typing goes beyond the right edge +================ +*/ +void Con_DrawInput (void) +{ + int y; + int i; + char *text; + + if (key_dest != key_console && !con_forcedup) + return; // don't draw anything + + text = key_lines[edit_line]; + +// add the cursor frame + text[key_linepos] = 10+((int)(realtime*con_cursorspeed)&1); + +// fill out remainder with spaces + for (i=key_linepos+1 ; i< con_linewidth ; i++) + text[i] = ' '; + +// prestep if horizontally scrolling + if (key_linepos >= con_linewidth) + text += 1 + key_linepos - con_linewidth; + +// draw it + y = con_vislines-16; + + for (i=0 ; i con_notifytime.value) + continue; + text = con_text + (i % con_totallines)*con_linewidth; + + clearnotify = 0; + scr_copytop = 1; + + for (x = 0 ; x < con_linewidth ; x++) + Draw_Character ( (x+1)<<3, v, text[x]); + + v += 8; + } + + + if (key_dest == key_message) + { + clearnotify = 0; + scr_copytop = 1; + + x = 0; + + Draw_String (8, v, "say:"); + while(chat_buffer[x]) + { + Draw_Character ( (x+5)<<3, v, chat_buffer[x]); + x++; + } + Draw_Character ( (x+5)<<3, v, 10+((int)(realtime*con_cursorspeed)&1)); + v += 8; + } + + if (v > con_notifylines) + con_notifylines = v; +} + +/* +================ +Con_DrawConsole + +Draws the console with the solid background +The typing input line at the bottom should only be drawn if typing is allowed +================ +*/ +void Con_DrawConsole (int lines, qboolean drawinput) { + int i, x, y, con_x, con_y; + int rows; + char *text; + int j; + + if (lines <= 0) + return; + +// draw the background + Draw_ConsoleBackground (lines); + +// draw the text + con_vislines = lines; + + rows = (lines-16)>>3; // rows of text to draw + y = lines - 16 - (rows<<3); // may start slightly negative + + for (i= con_current - rows + 1 ; i<=con_current ; i++, y+=8 ) { + j = i - con_backscroll; + if (j<0) + j = 0; + text = con_text + (j % con_totallines)*con_linewidth; + + for (x=0 ; x +#include +#include +#include +#include + +#include "cpu.h" + +/* Define this to the CPU frequency */ +#define CPU_FREQ 336000000 /* CPU clock: 336 MHz */ +#define CFG_EXTAL 12000000 /* EXT clock: 12 Mhz */ + +// SDRAM Timings, unit: ns +#define SDRAM_TRAS 45 /* RAS# Active Time */ +#define SDRAM_RCD 20 /* RAS# to CAS# Delay */ +#define SDRAM_TPC 20 /* RAS# Precharge Time */ +#define SDRAM_TRWL 7 /* Write Latency Time */ +#define SDRAM_TREF 15625 /* Refresh period: 4096 refresh cycles/64ms */ +//#define SDRAM_TREF 7812 /* Refresh period: 8192 refresh cycles/64ms */ + +#include "jz4740.h" + +static unsigned long jz_dev=0; +static volatile unsigned long *jz_cpmregl, *jz_emcregl; +volatile unsigned short *jz_emcregs; + +static inline int sdram_convert(unsigned int pllin,unsigned int *sdram_freq) +{ + register unsigned int ns, tmp; + + ns = 1000000000 / pllin; + /* Set refresh registers */ + tmp = SDRAM_TREF/ns; + tmp = tmp/64 + 1; + if (tmp > 0xff) tmp = 0xff; + *sdram_freq = tmp; + + return 0; + +} + +static int +pll_init(unsigned int clock) +{ + register unsigned int cfcr, plcr1; + unsigned int sdramclock = 0; + int n2FR[33] = { + 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, + 9 + }; + //int div[5] = {1, 4, 4, 4, 4}; /* divisors of I:S:P:L:M */ + int div[5] = {1, 3, 3, 3, 3}; /* divisors of I:S:P:L:M */ + int nf, pllout2; + + cfcr = CPM_CPCCR_CLKOEN | + (n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) | + (n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) | + (n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) | + (n2FR[div[3]] << CPM_CPCCR_MDIV_BIT) | + (n2FR[div[4]] << CPM_CPCCR_LDIV_BIT); + + pllout2 = (cfcr & CPM_CPCCR_PCS) ? clock : (clock / 2); + + /* Init UHC clock */ + // REG_CPM_UHCCDR = pllout2 / 48000000 - 1; + jz_cpmregl[0x6C>>2] = pllout2 / 48000000 - 1; + + nf = clock * 2 / CFG_EXTAL; + plcr1 = ((nf - 2) << CPM_CPPCR_PLLM_BIT) | /* FD */ + (0 << CPM_CPPCR_PLLN_BIT) | /* RD=0, NR=2 */ + (0 << CPM_CPPCR_PLLOD_BIT) | /* OD=0, NO=1 */ + (0x20 << CPM_CPPCR_PLLST_BIT) | /* PLL stable time */ + CPM_CPPCR_PLLEN; /* enable PLL */ + + /* init PLL */ + // REG_CPM_CPCCR = cfcr; + // REG_CPM_CPPCR = plcr1; + jz_cpmregl[0] = cfcr; + jz_cpmregl[0x10>>2] = plcr1; + + sdram_convert(clock,&sdramclock); + if (sdramclock > 0) { +// REG_EMC_RTCOR = sdramclock; +// REG_EMC_RTCNT = sdramclock; + jz_emcregs[0x8C>>1] = sdramclock; + jz_emcregs[0x88>>1] = sdramclock; + + } +} + +void +cpu_init() +{ + jz_dev = open("/dev/mem", O_RDWR); + jz_cpmregl=(unsigned long *)mmap(0, 0x80, PROT_READ|PROT_WRITE, MAP_SHARED, jz_dev, 0x10000000); + jz_emcregl=(unsigned long *)mmap(0, 0x90, PROT_READ|PROT_WRITE, MAP_SHARED, jz_dev, 0x13010000); + jz_emcregs=(unsigned short *)jz_emcregl; + +} + +void +cpu_deinit() +{ + cpu_set_clock( GP2X_MAX_CLOCK ); + munmap((void *)jz_cpmregl, 0x80); + munmap((void *)jz_emcregl, 0x90); + close(jz_dev); +// fcloseall(); + sync(); +} + +static void +loc_set_clock(int clock_in_mhz ) +{ + if (clock_in_mhz >= GP2X_MIN_CLOCK && clock_in_mhz <= GP2X_MAX_CLOCK) { + pll_init( clock_in_mhz * 1000000 ); + } +} + +static unsigned int loc_clock_in_mhz = GP2X_DEF_CLOCK; + +void +cpu_set_clock(unsigned int clock_in_mhz) +{ + if (clock_in_mhz == loc_clock_in_mhz) return; + loc_clock_in_mhz = clock_in_mhz; + + loc_set_clock(clock_in_mhz); + + return; +} + +unsigned int +cpu_get_clock() +{ + return loc_clock_in_mhz; +} + diff --git a/project/jni/application/quake/source/cpu.h b/project/jni/application/quake/source/cpu.h new file mode 100644 index 000000000..38e7e16cf --- /dev/null +++ b/project/jni/application/quake/source/cpu.h @@ -0,0 +1,40 @@ +/* + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __CPUDINGUX_H__ +#define __CPUDINGUX_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +# define GP2X_DEF_CLOCK 383 +# define GP2X_MIN_CLOCK 336 +# define GP2X_DEF_EMU_CLOCK 383 +# define GP2X_MAX_CLOCK 420 + +void cpu_init(void); +void cpu_deinit(void); + +extern unsigned int cpu_get_clock(void); +extern void cpu_set_clock(unsigned int clock_in_mhz); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/project/jni/application/quake/source/crc.c b/project/jni/application/quake/source/crc.c new file mode 100644 index 000000000..847c3cc08 --- /dev/null +++ b/project/jni/application/quake/source/crc.c @@ -0,0 +1,81 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/* crc.c */ + +#include "quakedef.h" +#include "crc.h" + +// this is a 16 bit, non-reflected CRC using the polynomial 0x1021 +// and the initial and final xor values shown below... in other words, the +// CCITT standard CRC used by XMODEM + +#define CRC_INIT_VALUE 0xffff +#define CRC_XOR_VALUE 0x0000 + +static unsigned short crctable[256] = +{ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +void CRC_Init(unsigned short *crcvalue) +{ + *crcvalue = CRC_INIT_VALUE; +} + +void CRC_ProcessByte(unsigned short *crcvalue, byte data) +{ + *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data]; +} + +unsigned short CRC_Value(unsigned short crcvalue) +{ + return crcvalue ^ CRC_XOR_VALUE; +} \ No newline at end of file diff --git a/project/jni/application/quake/source/crc.h b/project/jni/application/quake/source/crc.h new file mode 100644 index 000000000..7cc779c16 --- /dev/null +++ b/project/jni/application/quake/source/crc.h @@ -0,0 +1,24 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/* crc.h */ + +void CRC_Init(unsigned short *crcvalue); +void CRC_ProcessByte(unsigned short *crcvalue, byte data); +unsigned short CRC_Value(unsigned short crcvalue); diff --git a/project/jni/application/quake/source/cvar.c b/project/jni/application/quake/source/cvar.c new file mode 100644 index 000000000..d4a6b2399 --- /dev/null +++ b/project/jni/application/quake/source/cvar.c @@ -0,0 +1,310 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cvar.c -- dynamic variable tracking + +#include "quakedef.h" + +cvar_t *cvar_vars; +char *cvar_null_string = ""; + +// 2000-01-09 CvarList command by Maddes start + +/* + +========= + +Cvar_List + +========= + +*/ + +void Cvar_List_f (void) + +{ + + cvar_t *cvar; + + char *partial; + + int len; + + int count; + + + + if (Cmd_Argc() > 1) + + { + + partial = Cmd_Argv (1); + + len = Q_strlen(partial); + + } + + else + + { + + partial = NULL; + + len = 0; + + } + + + + count=0; + + for (cvar=cvar_vars ; cvar ; cvar=cvar->next) + + { + + if (partial && Q_strncmp (partial,cvar->name, len)) + + { + + continue; + + } + + Con_Printf ("\"%s\" is \"%s\"\n", cvar->name, cvar->string); + + count++; + + } + + + + Con_Printf ("%i cvar(s)", count); + + if (partial) + + { + + Con_Printf (" beginning with \"%s\"", partial); + + } + + Con_Printf ("\n"); + +} + +// 2000-01-09 CvarList command by Maddes end + +/* +============ +Cvar_FindVar +============ +*/ +cvar_t *Cvar_FindVar (char *var_name) +{ + cvar_t *var; + + for (var=cvar_vars ; var ; var=var->next) + if (!Q_strcmp (var_name, var->name)) + return var; + + return NULL; +} + +/* +============ +Cvar_VariableValue +============ +*/ +float Cvar_VariableValue (char *var_name) +{ + cvar_t *var; + + var = Cvar_FindVar (var_name); + if (!var) + return 0; + return Q_atof (var->string); +} + + +/* +============ +Cvar_VariableString +============ +*/ +char *Cvar_VariableString (char *var_name) +{ + cvar_t *var; + + var = Cvar_FindVar (var_name); + if (!var) + return cvar_null_string; + return var->string; +} + + +/* +============ +Cvar_CompleteVariable +============ +*/ +char *Cvar_CompleteVariable (char *partial) +{ + cvar_t *cvar; + int len; + + len = Q_strlen(partial); + + if (!len) + return NULL; + +// check functions + for (cvar=cvar_vars ; cvar ; cvar=cvar->next) + if (!Q_strncmp (partial,cvar->name, len)) + return cvar->name; + + return NULL; +} + + +/* +============ +Cvar_Set +============ +*/ +void Cvar_Set (char *var_name, char *value) +{ + cvar_t *var; + qboolean changed; + + var = Cvar_FindVar (var_name); + if (!var) + { // there is an error in C code if this happens + Con_Printf ("Cvar_Set: variable %s not found\n", var_name); + return; + } + + changed = Q_strcmp(var->string, value); + + Z_Free (var->string); // free the old value string + + var->string = Z_Malloc (Q_strlen(value)+1); + Q_strcpy (var->string, value); + var->value = Q_atof (var->string); + if (var->server && changed) + { + if (sv.active) + SV_BroadcastPrintf ("\"%s\" changed to \"%s\"\n", var->name, var->string); + } +} + +/* +============ +Cvar_SetValue +============ +*/ +void Cvar_SetValue (char *var_name, float value) +{ + char val[32]; + + sprintf (val, "%f",value); + Cvar_Set (var_name, val); +} + + +/* +============ +Cvar_RegisterVariable + +Adds a freestanding variable to the variable list. +============ +*/ +void Cvar_RegisterVariable (cvar_t *variable) +{ + char *oldstr; + +// first check to see if it has allready been defined + if (Cvar_FindVar (variable->name)) + { + Con_Printf ("Can't register variable %s, allready defined\n", variable->name); + return; + } + +// check for overlap with a command + if (Cmd_Exists (variable->name)) + { + Con_Printf ("Cvar_RegisterVariable: %s is a command\n", variable->name); + return; + } + +// copy the value off, because future sets will Z_Free it + oldstr = variable->string; + variable->string = Z_Malloc (Q_strlen(variable->string)+1); + Q_strcpy (variable->string, oldstr); + variable->value = Q_atof (variable->string); + +// link the variable in + variable->next = cvar_vars; + cvar_vars = variable; +} + +/* +============ +Cvar_Command + +Handles variable inspection and changing from the console +============ +*/ +qboolean Cvar_Command (void) +{ + cvar_t *v; + +// check variables + v = Cvar_FindVar (Cmd_Argv(0)); + if (!v) + return false; + +// perform a variable print or set + if (Cmd_Argc() == 1) + { + Con_Printf ("\"%s\" is \"%s\"\n", v->name, v->string); + return true; + } + + Cvar_Set (v->name, Cmd_Argv(1)); + return true; +} + + +/* +============ +Cvar_WriteVariables + +Writes lines containing "set variable value" for all variables +with the archive flag set to true. +============ +*/ +void Cvar_WriteVariables (FILE *f) +{ + cvar_t *var; + + for (var = cvar_vars ; var ; var = var->next) + if (var->archive) + fprintf (f, "%s \"%s\"\n", var->name, var->string); +} + diff --git a/project/jni/application/quake/source/cvar.h b/project/jni/application/quake/source/cvar.h new file mode 100644 index 000000000..f8c4a912a --- /dev/null +++ b/project/jni/application/quake/source/cvar.h @@ -0,0 +1,109 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cvar.h + +/* + +cvar_t variables are used to hold scalar or string variables that can be changed or displayed at the console or prog code as well as accessed directly +in C code. + +it is sufficient to initialize a cvar_t with just the first two fields, or +you can add a ,true flag for variables that you want saved to the configuration +file when the game is quit: + +cvar_t r_draworder = {"r_draworder","1"}; +cvar_t scr_screensize = {"screensize","1",true}; + +Cvars must be registered before use, or they will have a 0 value instead of the float interpretation of the string. Generally, all cvar_t declarations should be registered in the apropriate init function before any console commands are executed: +Cvar_RegisterVariable (&host_framerate); + + +C code usually just references a cvar in place: +if ( r_draworder.value ) + +It could optionally ask for the value to be looked up for a string name: +if (Cvar_VariableValue ("r_draworder")) + +Interpreted prog code can access cvars with the cvar(name) or +cvar_set (name, value) internal functions: +teamplay = cvar("teamplay"); +cvar_set ("registered", "1"); + +The user can access cvars from the console in two ways: +r_draworder prints the current value +r_draworder 0 sets the current value to 0 +Cvars are restricted from having the same names as commands to keep this +interface from being ambiguous. +*/ + +typedef struct cvar_s +{ + char *name; + char *string; + qboolean archive; // set to true to cause it to be saved to vars.rc + qboolean server; // notifies players when changed + float value; + struct cvar_s *next; +} cvar_t; + +typedef struct cvar_FPM_s +{ + char *name; + char *string; + qboolean archive; // set to true to cause it to be saved to vars.rc + qboolean server; // notifies players when changed + fixedpoint_t value; + struct cvar_FPM_s *next; +} cvar_FPM_t; + +void Cvar_List_f (void); // 2000-01-09 CvarList command by Maddes + +void Cvar_RegisterVariable (cvar_t *variable); +// registers a cvar that allready has the name, string, and optionally the +// archive elements set. + +void Cvar_Set (char *var_name, char *value); +// equivelant to " " typed at the console + +void Cvar_SetValue (char *var_name, float value); +// expands value to a string and calls Cvar_Set + +float Cvar_VariableValue (char *var_name); +// returns 0 if not defined or non numeric + +char *Cvar_VariableString (char *var_name); +// returns an empty string if not defined + +char *Cvar_CompleteVariable (char *partial); +// attempts to match a partial variable name for command line completion +// returns NULL if nothing fits + +qboolean Cvar_Command (void); +// called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known +// command. Returns true if the command was a variable reference that +// was handled. (print or change) + +void Cvar_WriteVariables (FILE *f); +// Writes lines containing "set variable value" for all variables +// with the archive flag set to true. + +cvar_t *Cvar_FindVar (char *var_name); + +extern cvar_t *cvar_vars; diff --git a/project/jni/application/quake/source/d_edge.c b/project/jni/application/quake/source/d_edge.c new file mode 100644 index 000000000..0935cd02f --- /dev/null +++ b/project/jni/application/quake/source/d_edge.c @@ -0,0 +1,738 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_edge.c + +#include "quakedef.h" +#include "d_local.h" +#include "LogFloat.h" + +static int miplevel; + +float scale_for_mip; +int screenwidth; +int ubasestep, errorterm, erroradjustup, erroradjustdown; +int vstartscan; + +#ifdef USEFPM +fixedpoint_t scale_for_mipFPM; +#endif + +// FIXME: should go away +extern void R_RotateBmodel (void); +extern void R_TransformFrustum (void); + +vec3_t transformed_modelorg; + +#ifdef USEFPM +extern void R_RotateBmodelFPM (void); +extern void R_TransformFrustumFPM (void); +vec3_FPM_t transformed_modelorgFPM; +#endif +/* +============== +D_DrawPoly + +============== +*/ +void D_DrawPoly (void) +{ +// this driver takes spans, not polygons +} + +#ifdef USEFPM +void D_DrawPolyFPM (void) +{ +// this driver takes spans, not polygons +} +#endif + +/* +============= +D_MipLevelForScale +============= +*/ +int D_MipLevelForScale (float scale) +{ + int lmiplevel; + + if (scale >= d_scalemip[0] ) + lmiplevel = 0; + else if (scale >= d_scalemip[1] ) + lmiplevel = 1; + else if (scale >= d_scalemip[2] ) + lmiplevel = 2; + else + lmiplevel = 3; + + if (lmiplevel < d_minmip) + lmiplevel = d_minmip; + + return lmiplevel; +} + +#ifdef USEFPM +int D_MipLevelForScaleFPM (fixedpoint_t scale) +{ + int lmiplevel; + + if (scale >= d_scalemipFPM[0] ) + lmiplevel = 0; + else if (scale >= d_scalemipFPM[1] ) + lmiplevel = 1; + else if (scale >= d_scalemipFPM[2] ) + lmiplevel = 2; + else + lmiplevel = 3; + + if (lmiplevel < d_minmip) + lmiplevel = d_minmip; + + return lmiplevel; +} +#endif + +/* +============== +D_DrawSolidSurface +============== +*/ + +// FIXME: clean this up + +void D_DrawSolidSurface (surf_t *surf, int color) +{ + espan_t *span; + byte *pdest; + int u, u2, pix; + + pix = (color<<24) | (color<<16) | (color<<8) | color; + for (span=surf->spans ; span ; span=span->pnext) + { + pdest = (byte *)d_viewbuffer + screenwidth*span->v; + u = span->u; + u2 = span->u + span->count - 1; + ((byte *)pdest)[u] = pix; + + if (u2 - u < 8) + { + for (u++ ; u <= u2 ; u++) + ((byte *)pdest)[u] = pix; + } + else + { + for (u++ ; u & 3 ; u++) + ((byte *)pdest)[u] = pix; + + u2 -= 4; + for ( ; u <= u2 ; u+=4) + *(int *)((byte *)pdest + u) = pix; + u2 += 4; + for ( ; u <= u2 ; u++) + ((byte *)pdest)[u] = pix; + } + } +} + +/* +============== +D_CalcGradients +============== +*/ +#ifndef USE_PQ_OPT3 +void D_CalcGradients (msurface_t *pface) +{ + mplane_t *pplane; + float mipscale; + vec3_t p_temp1; + vec3_t p_saxis, p_taxis; + float t; + + pplane = pface->plane; + + mipscale = (float)(1.0 / (float)(1 << miplevel)); + + //LogFloat((int)miplevel, "miplevel", -1, -1); + //LogFloat(mipscale, "mipscale", -1, -1); + + TransformVector (pface->texinfo->vecs[0], p_saxis); + TransformVector (pface->texinfo->vecs[1], p_taxis); + + //LogFloat(p_saxis[0], "p_saxis", 0, -1); + //LogFloat(p_saxis[1], "p_saxis", 1, -1); + //LogFloat(p_saxis[2], "p_saxis", 2, -1); + //LogFloat(p_taxis[0], "p_taxis", 0, -1); + //LogFloat(p_taxis[1], "p_taxis", 1, -1); + //LogFloat(p_taxis[2], "p_taxis", 2, -1); + + t = xscaleinv * mipscale; + d_sdivzstepu = p_saxis[0] * t; + d_tdivzstepu = p_taxis[0] * t; + + //LogFloat(xscaleinv, "xscaleinv", -1, -1); + //LogFloat(d_sdivzstepu, "d_sdivzstepu", -1, -1); + //LogFloat(d_tdivzstepu, "d_tdivzstepu", -1, -1); + + t = yscaleinv * mipscale; + d_sdivzstepv = -p_saxis[1] * t; + d_tdivzstepv = -p_taxis[1] * t; + + //LogFloat(yscaleinv, "yscaleinv", -1, -1); + //LogFloat(d_sdivzstepv, "d_sdivzstepv", -1, -1); + //LogFloat(d_tdivzstepv, "d_tdivzstepv", -1, -1); + + d_sdivzorigin = p_saxis[2] * mipscale - xcenter * d_sdivzstepu - + ycenter * d_sdivzstepv; + d_tdivzorigin = p_taxis[2] * mipscale - xcenter * d_tdivzstepu - + ycenter * d_tdivzstepv; + + //LogFloat(d_sdivzorigin, "d_sdivzorigin", -1, -1); + //LogFloat(d_tdivzorigin, "d_tdivzorigin", -1, -1); + + VectorScale (transformed_modelorg, mipscale, p_temp1); + + //LogFloat(p_temp1[0], "p_temp1", 0, -1); + //LogFloat(p_temp1[1], "p_temp1", 1, -1); + //LogFloat(p_temp1[2], "p_temp1", 2, -1); + + t = 0x10000*mipscale; + + //LogFloat(t, "t", -1, -1); + + sadjust = (int)(((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) - + ((pface->texturemins[0] << 16) >> miplevel) + + pface->texinfo->vecs[0][3]*t); + tadjust = (int)(((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) - + ((pface->texturemins[1] << 16) >> miplevel) + + pface->texinfo->vecs[1][3]*t); + + //LogFloat(sadjust, "sadjust", -1, -1); + //LogFloat(tadjust, "tadjust", -1, -1); +// +// -1 (-epsilon) so we never wander off the edge of the texture +// + bbextents = ((pface->extents[0] << 16) >> miplevel) - 1; + bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1; + + //LogFloat(bbextents, "bbextents", -1, -1); + //LogFloat(bbextentt, "bbextentt", -1, -1); +} +#else +void D_CalcGradients (msurface_t *pface) +{ + mplane_t *pplane; + int mipscale_fxp; + int p_temp1_fxp[3]; + int p_saxis_fxp[3], p_taxis_fxp[3]; + int t_fxp; + + pplane = pface->plane; + + //Dan: TODO: get miplevel ranges + mipscale_fxp = (1 << miplevel); + + //(26.6->11.21) / 24.8 = 19.13 + p_saxis_fxp[0]= (pface->texinfo->vecs_fxp[0][0]<<15)/vright_fxp[0]+ + (pface->texinfo->vecs_fxp[0][1]<<15)/vright_fxp[1]+ + (pface->texinfo->vecs_fxp[0][2]<<15)/vright_fxp[2]; + p_saxis_fxp[1]= (pface->texinfo->vecs_fxp[0][0]<<15)/vup_fxp[0]+ + (pface->texinfo->vecs_fxp[0][1]<<15)/vup_fxp[1]+ + (pface->texinfo->vecs_fxp[0][2]<<15)/vup_fxp[2]; + p_saxis_fxp[2]= (pface->texinfo->vecs_fxp[0][0]<<15)/vpn_fxp[0]+ + (pface->texinfo->vecs_fxp[0][1]<<15)/vpn_fxp[1]+ + (pface->texinfo->vecs_fxp[0][2]<<15)/vpn_fxp[2]; + + p_taxis_fxp[0]= (pface->texinfo->vecs_fxp[1][0]<<15)/vright_fxp[0]+ + (pface->texinfo->vecs_fxp[1][1]<<15)/vright_fxp[1]+ + (pface->texinfo->vecs_fxp[1][2]<<15)/vright_fxp[2]; + p_taxis_fxp[1]= (pface->texinfo->vecs_fxp[1][0]<<15)/vup_fxp[0]+ + (pface->texinfo->vecs_fxp[1][1]<<15)/vup_fxp[1]+ + (pface->texinfo->vecs_fxp[1][2]<<15)/vup_fxp[2]; + p_taxis_fxp[2]= (pface->texinfo->vecs_fxp[1][0]<<15)/vpn_fxp[0]+ + (pface->texinfo->vecs_fxp[1][1]<<15)/vpn_fxp[1]+ + (pface->texinfo->vecs_fxp[1][2]<<15)/vpn_fxp[2]; + + //TransformVector (pface->texinfo->vecs[0], p_saxis); + //TransformVector (pface->texinfo->vecs[1], p_taxis); + + //Dan: Maybe not enough precision here + //19.13 -> 3.29 / 9.23 = 26.6 + d_sdivzstepu_fxp=(p_saxis_fxp[0]<<16)/xscale_fxp; + //26.6 / 32.0 = 26.6 + d_sdivzstepu_fxp/=mipscale_fxp; + + //19.13 -> 3.29 / 9.23 = 26.6 + d_tdivzstepu_fxp=(p_taxis_fxp[0]<<16)/xscale_fxp; + //26.6 / 32.0 = 26.6 + d_sdivzstepu_fxp/=mipscale_fxp; + + //19.13 -> 3.29 / 9.23 = 26.6 + d_sdivzstepv_fxp=(p_saxis_fxp[1]<<16)/yscale_fxp; + //26.6 / 32.0 = 26.6 + d_sdivzstepv_fxp/=mipscale_fxp; + + //19.13 -> 3.29 / 9.23 = 26.6 + d_tdivzstepv_fxp=(p_taxis_fxp[1]<<16)/yscale_fxp; + //26.6 / 32.0 = 26.6 + d_tdivzstepv_fxp/=mipscale_fxp; + + //Dan: left off here + d_sdivzorigin = p_saxis_fxp[2] * mipscale_fxp - xcenter_fxp * d_sdivzstepu_fxp - + ycenter_fxp * d_sdivzstepv_fxp; + d_tdivzorigin = p_taxis_fxp[2] * mipscale_fxp - xcenter_fxp * d_tdivzstepu_fxp - + ycenter_fxp * d_tdivzstepv_fxp; + + VectorScale (transformed_modelorg, mipscale_fxp, p_temp1_fxp); + + t_fxp = 0x10000*mipscale_fxp; + sadjust = (int)(((fixed16_t)(DotProduct (p_temp1_fxp, p_saxis_fxp) * 0x10000 + 0.5)) - + ((pface->texturemins[0] << 16) >> miplevel) + + pface->texinfo->vecs_fxp[0][3]*t_fxp); + tadjust = (int)(((fixed16_t)(DotProduct (p_temp1_fxp, p_taxis_fxp) * 0x10000 + 0.5)) - + ((pface->texturemins[1] << 16) >> miplevel) + + pface->texinfo->vecs_fxp[1][3]*t_fxp); + +// +// -1 (-epsilon) so we never wander off the edge of the texture +// + bbextents = ((pface->extents[0] << 16) >> miplevel) - 1; + bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1; +} +#endif +/* +#else +//JB: Optimization +extern int fpxscale, fpyscale; +extern int fpxcenter, fpycenter; +static fpvec3 mo; +static float tmo; +void D_CalcGradients (msurface_t *pface) +{ + fpvec3 v0, v1, p_saxis, p_taxis, p_temp1; + int dps, dpt; + + v0[0] = (int)(16384.0f * pface->texinfo->vecs[0][0]); // 18.14 + v0[1] = (int)(16384.0f * pface->texinfo->vecs[0][1]); + v0[2] = (int)(16384.0f * pface->texinfo->vecs[0][2]); + v1[0] = (int)(16384.0f * pface->texinfo->vecs[1][0]); + v1[1] = (int)(16384.0f * pface->texinfo->vecs[1][1]); + v1[2] = (int)(16384.0f * pface->texinfo->vecs[1][2]); + + FPTransformVector (v0, p_saxis); + FPTransformVector (v1, p_taxis); + + sdivzstepu = ((p_saxis[0] >> miplevel) / fpxscale) << 8; + tdivzstepu = ((p_taxis[0] >> miplevel) / fpxscale) << 8; + sdivzstepv = ((-p_saxis[1] >> miplevel) / fpyscale) << 8; + tdivzstepv = ((-p_taxis[1] >> miplevel) / fpyscale) << 8; + sdivzorigin = ((p_saxis[2] >> 2) >> miplevel) - fpxcenter * (sdivzstepu >> 6) - fpycenter * (sdivzstepv >> 6); + tdivzorigin = ((p_taxis[2] >> 2) >> miplevel) - fpxcenter * (tdivzstepu >> 6) - fpycenter * (tdivzstepv >> 6); + + if (tmo != transformed_modelorg[0]) + { + tmo = transformed_modelorg[0]; + mo[0] = (int)(256.0f * transformed_modelorg[0]); + mo[1] = (int)(256.0f * transformed_modelorg[1]); + mo[2] = (int)(256.0f * transformed_modelorg[2]); + } + p_temp1[0] = mo[0] >> miplevel; + p_temp1[1] = mo[1] >> miplevel; + p_temp1[2] = mo[2] >> miplevel; + + dps = ((p_temp1[0] * (p_saxis[0] >> 14)) >> 2 ) + + ((p_temp1[1] * (p_saxis[1] >> 14)) >> 2 ) + + ((p_temp1[2] * (p_saxis[2] >> 14)) >> 2 ); + dpt = ((p_temp1[0] * (p_taxis[0] >> 14)) >> 2 ) + + ((p_temp1[1] * (p_taxis[1] >> 14)) >> 2 ) + + ((p_temp1[2] * (p_taxis[2] >> 14)) >> 2 ); + + sadjust = dps - (pface->texturemins[0] << (16 - miplevel)) + ((int)(pface->texinfo->vecs[0][3]) << (16 - miplevel)); + tadjust = dpt - (pface->texturemins[1] << (16 - miplevel)) + ((int)(pface->texinfo->vecs[1][3]) << (16 - miplevel)); + bbextents = ((pface->extents[0] << 16) >> miplevel) - 1; + bbextentt = ((pface->extents[1] << 16) >> miplevel) - 1; +} +#endif +*/ +/* +============== +D_DrawSurfaces +============== +*/ +#ifndef USE_PQ_OPT + + +void D_DrawSurfaces (void) +{ + surf_t *s; + msurface_t *pface; + surfcache_t *pcurrentcache; + vec3_t world_transformed_modelorg; + vec3_t local_modelorg; + + + currententity = &cl_entities[0]; + TransformVector (modelorg, transformed_modelorg); + VectorCopy (transformed_modelorg, world_transformed_modelorg); + +// TODO: could preset a lot of this at mode set time + if (r_drawflat.value) + { + for (s = &surfaces[1] ; sspans) + continue; + + // r_drawnpolycount++; + /* +#ifndef USE_PQ_OPT3 + d_zistepu = s->d_zistepu; + d_zistepv = s->d_zistepv; + d_ziorigin = s->d_ziorigin; +#else + d_zistepu_fxp = s->d_zistepu_fxp; + d_zistepv_fxp = s->d_zistepv_fxp; + d_ziorigin_fxp = s->d_ziorigin_fxp; +#endif + */ + pface = s->data; + char *surfcol; + + surfcol=(char *)((byte*) pface->texinfo->texture + sizeof(texture_t)); + // GpError(va("%d",(int)*((byte*) tx + tx->offsets[0]) & 0xFF),666); + D_DrawSolidSurface (s, surfcol[0] & 0xFF); + //D_DrawSolidSurface (s, (int)s->data & 0xFF); + D_DrawZSpans (s->spans); + } + } + else + { + for (s = &surfaces[1] ; sspans) + continue; + + r_drawnpolycount++; + +#ifndef USE_PQ_OPT3 + d_zistepu = s->d_zistepu; + d_zistepv = s->d_zistepv; + d_ziorigin = s->d_ziorigin; +#else + d_zistepu_fxp = s->d_zistepu_fxp; + d_zistepv_fxp = s->d_zistepv_fxp; + d_ziorigin_fxp = s->d_ziorigin_fxp; + + //d_zistepu = s->d_zistepu_fxp/4194304.0f; + //d_zistepv = s->d_zistepv_fxp/4194304.0f; + //d_ziorigin = s->d_ziorigin_fxp/4194304.0f; +#endif + + if (s->flags & SURF_DRAWSKY) + { + extern cvar_t r_fastsky; + extern cvar_t r_skycolor; + + if (r_fastsky.value) + D_DrawSolidSurface (s, (int)r_skycolor.value & 0xFF); + else { + if (!r_skymade) + { + R_MakeSky (); + } + + D_DrawSkyScans8 (s->spans); + } + D_DrawZSpans (s->spans); + } + else if (s->flags & SURF_DRAWBACKGROUND) + { + // set up a gradient for the background surface that places it + // effectively at infinity distance from the viewpoint + d_zistepu = 0; + d_zistepv = 0; + d_ziorigin = (float)-0.9; + + D_DrawSolidSurface (s, (int)r_clearcolor.value & 0xFF); + D_DrawZSpans (s->spans); + } + else if (s->flags & SURF_DRAWTURB) + { + extern cvar_t r_fastturb; + if (r_fastturb.value) { + texture_t *tx; + + pface = s->data; + tx = pface->texinfo->texture; + D_DrawSolidSurface (s, *((byte*) tx + tx->offsets[0] + ((tx->width * tx->height) >> 1))); + D_DrawZSpans(s->spans); + continue; + } + pface = s->data; + miplevel = 0; + cacheblock = (pixel_t *) + ((byte *)pface->texinfo->texture + + pface->texinfo->texture->offsets[0]); + cachewidth = 64; + + if (s->insubmodel) + { + // FIXME: we don't want to do all this for every polygon! + // TODO: store once at start of frame + currententity = s->entity; //FIXME: make this passed in to + // R_RotateBmodel () + VectorSubtract (r_origin, currententity->origin, + local_modelorg); + TransformVector (local_modelorg, transformed_modelorg); + + R_RotateBmodel (); // FIXME: don't mess with the frustum, + // make entity passed in + } + + D_CalcGradients (pface); + Turbulent8 (s->spans); + D_DrawZSpans (s->spans); + + if (s->insubmodel) + { + // + // restore the old drawing state + // FIXME: we don't want to do this every time! + // TODO: speed up + // + currententity = &cl_entities[0]; + VectorCopy (world_transformed_modelorg, + transformed_modelorg); + VectorCopy (base_vpn, vpn); + VectorCopy (base_vup, vup); + VectorCopy (base_vright, vright); + VectorCopy (base_modelorg, modelorg); + R_TransformFrustum (); + } + } + else + { + if (s->insubmodel) + { + // FIXME: we don't want to do all this for every polygon! + // TODO: store once at start of frame + currententity = s->entity; //FIXME: make this passed in to + // R_RotateBmodel () + VectorSubtract (r_origin, currententity->origin, local_modelorg); + TransformVector (local_modelorg, transformed_modelorg); + + R_RotateBmodel (); // FIXME: don't mess with the frustum, + // make entity passed in + } + + pface = s->data; + miplevel = D_MipLevelForScale (s->nearzi * scale_for_mip + * pface->texinfo->mipadjust); + + // FIXME: make this passed in to D_CacheSurface + pcurrentcache = D_CacheSurface (pface, miplevel); + + cacheblock = (pixel_t *)pcurrentcache->data; + cachewidth = pcurrentcache->width; + + D_CalcGradients (pface); + + (*d_drawspans) (s->spans); + + D_DrawZSpans (s->spans); + + if (s->insubmodel) + { + // + // restore the old drawing state + // FIXME: we don't want to do this every time! + // TODO: speed up + // + currententity = &cl_entities[0]; + VectorCopy (world_transformed_modelorg, + transformed_modelorg); + VectorCopy (base_vpn, vpn); + VectorCopy (base_vup, vup); + VectorCopy (base_vright, vright); + VectorCopy (base_modelorg, modelorg); + R_TransformFrustum (); + } + } + } + } +} +#else +//JB: Optimization +void D_DrawSurfaces (void) +{ + surf_t *s; + msurface_t *pface; + surfcache_t *pcurrentcache; + vec3_t world_transformed_modelorg; + vec3_t local_modelorg; + + currententity = &cl_entities[0]; + TransformVector (modelorg, transformed_modelorg); + VectorCopy (transformed_modelorg, world_transformed_modelorg); + +// TODO: could preset a lot of this at mode set time + if (r_drawflat.value) + { + for (s = &surfaces[1] ; sspans) + continue; + + zistepu = (int)(4194304.0f * s->d_zistepu); + zistepv = (int)(4194304.0f * s->d_zistepv); + ziorigin = (int)(4194304.0f * s->d_ziorigin); + + D_DrawSolidSurface (s, (int)s->data & 0xFF); + D_DrawZSpans (s->spans); + } + } + else + { + for (s = &surfaces[1] ; sspans) + continue; + + r_drawnpolycount++; + + zistepu = (int)(4194304.0f * s->d_zistepu); + zistepv = (int)(4194304.0f * s->d_zistepv); + ziorigin = (int)(4194304.0f * s->d_ziorigin); + + if (s->flags & SURF_DRAWSKY) + { + if (!r_skymade) + { + R_MakeSky (); + } + + D_DrawSkyScans8 (s->spans); + D_DrawZSpans (s->spans); + } + else if (s->flags & SURF_DRAWBACKGROUND) + { + // set up a gradient for the background surface that places it + // effectively at infinity distance from the viewpoint + zistepu = 0; + zistepv = 0; + ziorigin = 3774873; + + D_DrawSolidSurface (s, (int)r_clearcolor.value & 0xFF); + D_DrawZSpans (s->spans); + } + else if (s->flags & SURF_DRAWTURB) + { + pface = s->data; + miplevel = 0; + cacheblock = (pixel_t *) + ((byte *)pface->texinfo->texture + + pface->texinfo->texture->offsets[0]); + cachewidth = 64; + + if (s->insubmodel) + { + // FIXME: we don't want to do all this for every polygon! + // TODO: store once at start of frame + currententity = s->entity; //FIXME: make this passed in to + // R_RotateBmodel () + VectorSubtract (r_origin, currententity->origin, + local_modelorg); + TransformVector (local_modelorg, transformed_modelorg); + + R_RotateBmodel (); // FIXME: don't mess with the frustum, + // make entity passed in + } + + D_CalcGradients (pface); + Turbulent8 (s->spans); + D_DrawZSpans (s->spans); + + if (s->insubmodel) + { + // + // restore the old drawing state + // FIXME: we don't want to do this every time! + // TODO: speed up + // + currententity = &cl_entities[0]; + VectorCopy (world_transformed_modelorg, + transformed_modelorg); + VectorCopy (base_vpn, vpn); + VectorCopy (base_vup, vup); + VectorCopy (base_vright, vright); + VectorCopy (base_modelorg, modelorg); + R_TransformFrustum (); + } + } + else + { + if (s->insubmodel) + { + // FIXME: we don't want to do all this for every polygon! + // TODO: store once at start of frame + currententity = s->entity; //FIXME: make this passed in to + // R_RotateBmodel () + VectorSubtract (r_origin, currententity->origin, local_modelorg); + TransformVector (local_modelorg, transformed_modelorg); + + R_RotateBmodel (); // FIXME: don't mess with the frustum, + // make entity passed in + } + + pface = s->data; + miplevel = D_MipLevelForScale (s->nearzi * scale_for_mip + * pface->texinfo->mipadjust); + + // FIXME: make this passed in to D_CacheSurface + pcurrentcache = D_CacheSurface (pface, miplevel); + + cacheblock = (pixel_t *)pcurrentcache->data; + cachewidth = pcurrentcache->width; + + D_CalcGradients (pface); + + D_DrawSpans8WithZ(s->spans); + + // D_DrawZSpans (s->spans); + + if (s->insubmodel) + { + // + // restore the old drawing state + // FIXME: we don't want to do this every time! + // TODO: speed up + // + currententity = &cl_entities[0]; + VectorCopy (world_transformed_modelorg, + transformed_modelorg); + VectorCopy (base_vpn, vpn); + VectorCopy (base_vup, vup); + VectorCopy (base_vright, vright); + VectorCopy (base_modelorg, modelorg); + R_TransformFrustum (); + } + } + } + } +} +#endif diff --git a/project/jni/application/quake/source/d_fill.c b/project/jni/application/quake/source/d_fill.c new file mode 100644 index 000000000..7807c1482 --- /dev/null +++ b/project/jni/application/quake/source/d_fill.c @@ -0,0 +1,88 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_clear: clears a specified rectangle to the specified color + +#include "quakedef.h" + + +/* +================ +D_FillRect +================ +*/ +void D_FillRect (vrect_t *rect, int color) +{ + int rx, ry, rwidth, rheight; + unsigned char *dest; + unsigned *ldest; + + rx = rect->x; + ry = rect->y; + rwidth = rect->width; + rheight = rect->height; + + if (rx < 0) + { + rwidth += rx; + rx = 0; + } + if (ry < 0) + { + rheight += ry; + ry = 0; + } + if (rx+rwidth > (int)vid.width) //Dan: added cast to prevent warning + rwidth = vid.width - rx; + if (ry+rheight > (int)vid.height) //Dan: added cast to prevent warning + rheight = vid.height - rx; + + if (rwidth < 1 || rheight < 1) + return; + + dest = ((byte *)vid.buffer + ry*vid.rowbytes + rx); + + if (((rwidth & 0x03) == 0) && (((long)dest & 0x03) == 0)) + { + // faster aligned dword clear + ldest = (unsigned *)dest; + color += color << 16; + + rwidth >>= 2; + color += color << 8; + + for (ry=0 ; ry 3) + d_minmip = 3; + else if (d_minmip < 0) + d_minmip = 0; + + for (i=0 ; i<(NUM_MIPS-1) ; i++) + d_scalemip[i] = basemip[i] * d_mipscale.value; + +/*#if id386 + if (d_subdiv16.value) + d_drawspans = D_DrawSpans16; + else + d_drawspans = D_DrawSpans8; +#else*/ + d_drawspans = D_DrawSpans8; +//#endif + + d_aflatcolor = 0; +} + +#ifdef USEFPM +void D_SetupFrameFPM (void) +{ + int i; + fixedpoint_t d_mipscale_value=FPM_FROMFLOAT(d_mipscale.value); + + if (r_dowarp) + d_viewbuffer = r_warpbuffer; + else + d_viewbuffer = (void *)(byte *)vid.buffer; + + if (r_dowarp) + screenwidth = WARP_WIDTH; + else + screenwidth = vid.rowbytes; + + d_roverwrapped = false; + d_initial_roverFPM = sc_roverFPM; + + d_minmip = (int)d_mipcap.value; + if (d_minmip > 3) + d_minmip = 3; + else if (d_minmip < 0) + d_minmip = 0; + + for (i=0 ; i<(NUM_MIPS-1) ; i++) + d_scalemipFPM[i] = FPM_MUL(basemipFPM[i], d_mipscale_value); + +//Dan: id386 is not defined for Pocket PC builds +#if id386 + if (d_subdiv16.value) + d_drawspans = D_DrawSpans16; + else + d_drawspans = D_DrawSpans8; +#else + d_drawspans = D_DrawSpans8FPM; // FPM version doesn't seem to exist + d_drawspans = D_DrawSpans8; +#endif + + d_aflatcolor = 0; +} +#endif + +/* +=============== +D_UpdateRects +=============== +*/ +void D_UpdateRects (vrect_t *prect) +{ + +// the software driver draws these directly to the vid buffer + + UNUSED(prect); +} + diff --git a/project/jni/application/quake/source/d_local.h b/project/jni/application/quake/source/d_local.h new file mode 100644 index 000000000..83d9914b6 --- /dev/null +++ b/project/jni/application/quake/source/d_local.h @@ -0,0 +1,160 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_local.h: private rasterization driver defs + +#include "r_shared.h" + +// +// TODO: fine-tune this; it's based on providing some overage even if there +// is a 2k-wide scan, with subdivision every 8, for 256 spans of 12 bytes each +// +#define SCANBUFFERPAD 0x1000 + +#define R_SKY_SMASK 0x007F0000 +#define R_SKY_TMASK 0x007F0000 + +#define DS_SPAN_LIST_END -128 + +#define SURFCACHE_SIZE_AT_320X200 600*1024 + +typedef struct surfcache_s +{ + struct surfcache_s *next; + struct surfcache_s **owner; // NULL is an empty chunk of memory + int lightadj[MAXLIGHTMAPS]; // checked for strobe flush + int dlight; + int size; // including header + unsigned width; + unsigned height; // DEBUG only needed for debug + float mipscale; + struct texture_s *texture; // checked for animating textures + byte data[4]; // width*height elements +} surfcache_t; + +typedef struct surfcache_FPM_s +{ + struct surfcache_FPM_s *next; + struct surfcache_FPM_s **owner; // NULL is an empty chunk of memory + int lightadj[MAXLIGHTMAPS]; // checked for strobe flush + int dlight; + int size; // including header + unsigned width; + unsigned height; // DEBUG only needed for debug + fixedpoint_t mipscale; + struct texture_s *texture; // checked for animating textures + byte data[4]; // width*height elements +} surfcache_FPM_t; + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct sspan_s +{ + int u, v, count; +} sspan_t; + +extern cvar_t d_subdiv16; + +extern float scale_for_mip; +extern fixedpoint_t scale_for_mipFPM; + +extern qboolean d_roverwrapped; +extern surfcache_t *sc_rover; +extern surfcache_FPM_t *sc_roverFPM; +extern surfcache_t *d_initial_rover; +extern surfcache_FPM_t *d_initial_roverFPM; + +extern float d_sdivzstepu, d_tdivzstepu, d_zistepu; +extern float d_sdivzstepv, d_tdivzstepv, d_zistepv; +extern float d_sdivzorigin, d_tdivzorigin, d_ziorigin; + +extern int d_zistepu_fxp, d_zistepv_fxp, d_ziorigin_fxp; + +#ifdef USE_PQ_OPT3 +extern int d_sdivzstepu_fxp, d_tdivzstepu_fxp, d_zistepu_fxp; +extern int d_sdivzstepv_fxp, d_tdivzstepv_fxp, d_zistepv_fxp; +extern int d_sdivzorigin_fxp, d_tdivzorigin_fxp, d_ziorigin_fxp; +#endif + + +#ifdef USE_PQ_OPT +//JB:Optimization +extern int sdivzstepu, tdivzstepu, zistepu; +extern int sdivzstepv, tdivzstepv, zistepv; +extern int sdivzorigin, tdivzorigin, ziorigin; +#endif + +extern fixedpoint_t d_sdivzstepuFPM, d_tdivzstepuFPM, d_zistepuFPM; +extern fixedpoint_t d_sdivzstepvFPM, d_tdivzstepvFPM, d_zistepvFPM; +extern fixedpoint_t d_sdivzoriginFPM, d_tdivzoriginFPM, d_zioriginFPM; + +//Dan: ID Software was already using a minute amount of fixed point. I duplicated +//these just for consistancy in the conversion, and so the types would match. +fixed16_t sadjust, tadjust; +fixed16_t bbextents, bbextentt; +fixedpoint_t sadjustFPM, tadjustFPM; +fixedpoint_t bbextentsFPM, bbextenttFPM; + + +void D_DrawSpans8 (espan_t *pspans); +#ifdef USE_PQ_OPT +//JB:Optimization +void D_DrawSpans8WithZ (espan_t *pspans); +#endif +void D_DrawSpans8FPM (espan_t *pspans); +void D_DrawSpans16 (espan_t *pspans); +void D_DrawZSpans (espan_t *pspans); +void Turbulent8 (espan_t *pspan); +void D_SpriteDrawSpans (sspan_t *pspan); + +void D_DrawSkyScans8 (espan_t *pspan); +void D_DrawSkyScans8FPM (espan_t *pspan); +void D_DrawSkyScans16 (espan_t *pspan); + +void R_ShowSubDiv (void); +void (*prealspandrawer)(void); +surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel); +//surfcache_FPM_t *D_CacheSurfaceFPM (msurface_FPM_t *surface, int miplevel); + +extern int D_MipLevelForScale (float scale); + +#if id386 +extern void D_PolysetAff8Start (void); +extern void D_PolysetAff8End (void); +#endif + +extern short *d_pzbuffer; +extern unsigned int d_zrowbytes, d_zwidth; + +extern int *d_pscantable; +extern int d_scantable[MAXHEIGHT]; + +extern int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle; + +extern int d_y_aspect_shift, d_pix_min, d_pix_max, d_pix_shift; + +extern pixel_t *d_viewbuffer; + +extern short *zspantable[MAXHEIGHT]; + +extern int d_minmip; +extern float d_scalemip[3]; +extern fixedpoint_t d_scalemipFPM[3]; + +extern void (*d_drawspans) (espan_t *pspan); + diff --git a/project/jni/application/quake/source/d_modech.c b/project/jni/application/quake/source/d_modech.c new file mode 100644 index 000000000..b0ed0a0a7 --- /dev/null +++ b/project/jni/application/quake/source/d_modech.c @@ -0,0 +1,161 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_modech.c: called when mode has just changed + +#include "quakedef.h" +#include "d_local.h" + +int d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle; + +int d_y_aspect_shift, d_pix_min, d_pix_max, d_pix_shift; + +int d_scantable[MAXHEIGHT]; +short *zspantable[MAXHEIGHT]; + +//Dan East: +extern int min_vid_width; + +/* +================ +D_Patch +================ +*/ +void D_Patch (void) +{ +#if id386 + + static qboolean protectset8 = false; + + if (!protectset8) + { + Sys_MakeCodeWriteable ((int)D_PolysetAff8Start, + (int)D_PolysetAff8End - (int)D_PolysetAff8Start); + protectset8 = true; + } + +#endif // id386 +} + + +/* +================ +D_ViewChanged +================ +*/ +void D_ViewChanged (void) +{ + int rowbytes; + + if (r_dowarp) + rowbytes = WARP_WIDTH; + else + rowbytes = vid.rowbytes; + + scale_for_mip = xscale; + if (yscale > xscale) + scale_for_mip = yscale; + + d_zrowbytes = vid.width * 2; + d_zwidth = vid.width; + + d_pix_min = r_refdef.vrect.width / min_vid_width/*320*/; + if (d_pix_min < 1) + d_pix_min = 1; + + d_pix_max = (int)((float)r_refdef.vrect.width / (320.0 / 4.0) + 0.5); + d_pix_shift = 8 - (int)((float)r_refdef.vrect.width / 320.0 + 0.5); + if (d_pix_max < 1) + d_pix_max = 1; + + if (pixelAspect > 1.4) + d_y_aspect_shift = 1; + else + d_y_aspect_shift = 0; + + d_vrectx = r_refdef.vrect.x; + d_vrecty = r_refdef.vrect.y; + d_vrectright_particle = r_refdef.vrectright - d_pix_max; + d_vrectbottom_particle = + r_refdef.vrectbottom - (d_pix_max << d_y_aspect_shift); + + { + //Dan: changed to unsigned to shut compiler up + unsigned int i; + + for (i=0 ; i xscaleFPM) + scale_for_mipFPM = yscaleFPM; + + d_zrowbytes = vid.width * 2; + d_zwidth = vid.width; + + d_pix_min = r_refdef.vrect.width / min_vid_width/*320*/; + if (d_pix_min < 1) + d_pix_min = 1; + + d_pix_max = FPM_TOLONG(FPM_ADD(FPM_DIV(r_refdef.vrect.width, FPM_FROMFLOAT(320.0 / 4.0)), FPM_FROMFLOAT(0.5))); + d_pix_shift = 8 - FPM_TOLONG(FPM_ADD(FPM_DIV(r_refdef.vrect.width, FPM_FROMFLOAT(320.0)), FPM_FROMFLOAT(0.5))); + if (d_pix_max < 1) + d_pix_max = 1; + + if (pixelAspectFPM > FPM_FROMFLOAT(1.4)) + d_y_aspect_shift = 1; + else + d_y_aspect_shift = 0; + + d_vrectx = r_refdef.vrect.x; + d_vrecty = r_refdef.vrect.y; + d_vrectright_particle = r_refdef.vrectright - d_pix_max; + d_vrectbottom_particle = + r_refdef.vrectbottom - (d_pix_max << d_y_aspect_shift); + + { + unsigned int i; + + for (i=0 ; iorg, r_origin, local); + + transformed[0] = DotProduct(local, r_pright); + transformed[1] = DotProduct(local, r_pup); + transformed[2] = DotProduct(local, r_ppn); + + if (transformed[2] < PARTICLE_Z_CLIP) + return; + +// project the point +// FIXME: preadjust xcenter and ycenter + zi = (float)(1.0 / transformed[2]); + u = (int)(xcenter + zi * transformed[0] + 0.5); + v = (int)(ycenter - zi * transformed[1] + 0.5); + + if ((v > d_vrectbottom_particle) || + (u > d_vrectright_particle) || + (v < d_vrecty) || + (u < d_vrectx)) + { + return; + } + + pz = d_pzbuffer + (d_zwidth * v) + u; + pdest = d_viewbuffer + d_scantable[v] + u; + izi = (int)(zi * 0x8000); + + pix = izi >> d_pix_shift; + + if (pix < d_pix_min) + pix = d_pix_min; + else if (pix > d_pix_max) + pix = d_pix_max; + + switch (pix) + { + case 1: + count = 1 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { + pz[0] = izi; + pdest[0] = (byte)pparticle->color; + } + } + break; + + case 2: + count = 2 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { + pz[0] = izi; + pdest[0] = (byte)pparticle->color; + } + + if (pz[1] <= izi) + { + pz[1] = izi; + pdest[1] = (byte)pparticle->color; + } + } + break; + + case 3: + count = 3 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { + pz[0] = izi; + pdest[0] = (byte)pparticle->color; + } + + if (pz[1] <= izi) + { + pz[1] = izi; + pdest[1] = (byte)pparticle->color; + } + + if (pz[2] <= izi) + { + pz[2] = izi; + pdest[2] = (byte)pparticle->color; + } + } + break; + + case 4: + count = 4 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { + pz[0] = izi; + pdest[0] = (byte)pparticle->color; + } + + if (pz[1] <= izi) + { + pz[1] = izi; + pdest[1] = (byte)pparticle->color; + } + + if (pz[2] <= izi) + { + pz[2] = izi; + pdest[2] = (byte)pparticle->color; + } + + if (pz[3] <= izi) + { + pz[3] = izi; + pdest[3] = (byte)pparticle->color; + } + } + break; + + default: + count = pix << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + for (i=0 ; icolor; + } + } + } + break; + } +} + +#ifdef USEFPM +void D_DrawParticleFPM (particle_FPM_t *pparticle) +{ + vec3_FPM_t local, transformed; + fixedpoint_t zi; + byte *pdest; + short *pz; + int i, izi, pix, count, u, v; + +// transform point + VectorSubtractFPM (pparticle->org, r_originFPM, local); + + transformed[0] = DotProductFPM(local, r_prightFPM); + transformed[1] = DotProductFPM(local, r_pupFPM); + transformed[2] = DotProductFPM(local, r_ppnFPM); + + if (transformed[2] < PARTICLE_Z_CLIP_FPM) + return; + +// project the point +// FIXME: preadjust xcenter and ycenter + zi = FPM_DIV(FPM_FROMFLOAT(1.0), transformed[2]); + u = FPM_TOLONG(FPM_ADD3(xcenterFPM, FPM_MUL(zi, transformed[0]), FPM_FROMFLOAT(0.5))); + v = FPM_TOLONG(FPM_SUB(ycenterFPM, FPM_ADD(FPM_MUL(zi, transformed[1]), FPM_FROMFLOAT(0.5)))); + + if ((v > d_vrectbottom_particle) || + (u > d_vrectright_particle) || + (v < d_vrecty) || + (u < d_vrectx)) + { + return; + } + + pz = d_pzbuffer + (d_zwidth * v) + u; + pdest = d_viewbuffer + d_scantable[v] + u; + izi = FPM_TOLONG(FPM_MUL(zi, FPM_FROMLONG(0x8000))); + + pix = izi >> d_pix_shift; + + if (pix < d_pix_min) + pix = d_pix_min; + else if (pix > d_pix_max) + pix = d_pix_max; + + switch (pix) + { + case 1: + count = 1 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { + pz[0] = izi; + pdest[0] = pparticle->color; + } + } + break; + + case 2: + count = 2 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { + pz[0] = izi; + pdest[0] = pparticle->color; + } + + if (pz[1] <= izi) + { + pz[1] = izi; + pdest[1] = pparticle->color; + } + } + break; + + case 3: + count = 3 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { + pz[0] = izi; + pdest[0] = pparticle->color; + } + + if (pz[1] <= izi) + { + pz[1] = izi; + pdest[1] = pparticle->color; + } + + if (pz[2] <= izi) + { + pz[2] = izi; + pdest[2] = pparticle->color; + } + } + break; + + case 4: + count = 4 << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + if (pz[0] <= izi) + { + pz[0] = izi; + pdest[0] = pparticle->color; + } + + if (pz[1] <= izi) + { + pz[1] = izi; + pdest[1] = pparticle->color; + } + + if (pz[2] <= izi) + { + pz[2] = izi; + pdest[2] = pparticle->color; + } + + if (pz[3] <= izi) + { + pz[3] = izi; + pdest[3] = pparticle->color; + } + } + break; + + default: + count = pix << d_y_aspect_shift; + + for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth) + { + for (i=0 ; icolor; + } + } + } + break; + } +} +#endif +#endif // !id386 + diff --git a/project/jni/application/quake/source/d_polyse.c b/project/jni/application/quake/source/d_polyse.c new file mode 100644 index 000000000..6c8f639cb --- /dev/null +++ b/project/jni/application/quake/source/d_polyse.c @@ -0,0 +1,1209 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_polyset.c: routines for drawing sets of polygons sharing the same +// texture (used for Alias models) + +#include "quakedef.h" +#include "r_local.h" +#include "d_local.h" + + // 1 extra for spanpackage that marks end +/* +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct { + void *pdest; + short *pz; + int count; + byte *ptex; + int sfrac, tfrac, light, zi; +} spanpackage_t; +*/ + +typedef struct { + int isflattop; + int numleftedges; + int *pleftedgevert0; + int *pleftedgevert1; + int *pleftedgevert2; + int numrightedges; + int *prightedgevert0; + int *prightedgevert1; + int *prightedgevert2; +} edgetable; + +int r_p0[6], r_p1[6], r_p2[6]; + +byte *d_pcolormap; + +int d_aflatcolor; +int d_xdenom; + +edgetable *pedgetable; + +edgetable edgetables[12] = { + {0, 1, r_p0, r_p2, NULL, 2, r_p0, r_p1, r_p2 }, + {0, 2, r_p1, r_p0, r_p2, 1, r_p1, r_p2, NULL}, + {1, 1, r_p0, r_p2, NULL, 1, r_p1, r_p2, NULL}, + {0, 1, r_p1, r_p0, NULL, 2, r_p1, r_p2, r_p0 }, + {0, 2, r_p0, r_p2, r_p1, 1, r_p0, r_p1, NULL}, + {0, 1, r_p2, r_p1, NULL, 1, r_p2, r_p0, NULL}, + {0, 1, r_p2, r_p1, NULL, 2, r_p2, r_p0, r_p1 }, + {0, 2, r_p2, r_p1, r_p0, 1, r_p2, r_p0, NULL}, + {0, 1, r_p1, r_p0, NULL, 1, r_p1, r_p2, NULL}, + {1, 1, r_p2, r_p1, NULL, 1, r_p0, r_p1, NULL}, + {1, 1, r_p1, r_p0, NULL, 1, r_p2, r_p0, NULL}, + {0, 1, r_p0, r_p2, NULL, 1, r_p0, r_p1, NULL}, +}; + +// FIXME: some of these can become statics +int a_sstepxfrac, a_tstepxfrac, r_lstepx, a_ststepxwhole; +int r_sstepx, r_tstepx, r_lstepy, r_sstepy, r_tstepy; +int r_zistepx, r_zistepy; +int d_aspancount, d_countextrastep; + +spanpackage_t *a_spans; +spanpackage_t *d_pedgespanpackage; +static int ystart; +byte *d_pdest, *d_ptex; +short *d_pz; +int d_sfrac, d_tfrac, d_light, d_zi; +int d_ptexextrastep, d_sfracextrastep; +int d_tfracextrastep, d_lightextrastep, d_pdestextrastep; +int d_lightbasestep, d_pdestbasestep, d_ptexbasestep; +int d_sfracbasestep, d_tfracbasestep; +int d_ziextrastep, d_zibasestep; +int d_pzextrastep, d_pzbasestep; + + +typedef struct { + int quotient; + int remainder; +} adivtab_t; + +static adivtab_t adivtab[32*32] = { +#include "adivtab.h" +}; + +byte *skintable[MAX_LBM_HEIGHT]; +int skinwidth; +byte *skinstart; + +void D_PolysetDrawSpans8 (spanpackage_t *pspanpackage); +void D_PolysetCalcGradients (int skinwidth); +void D_DrawSubdiv (void); +void D_DrawNonSubdiv (void); +void D_PolysetRecursiveTriangle (int *p1, int *p2, int *p3); +void D_PolysetSetEdgeTable (void); +void D_RasterizeAliasPolySmooth (void); +void D_PolysetScanLeftEdge (int height); + +#if !id386 + +//extern spanpackage_t *spans; + + +/* +================ +D_PolysetDraw +================ +*/ +#ifndef USE_PQ_OPT +void D_PolysetDraw (void) +{ +spanpackage_t spans[DPS_MAXSPANS + 1 + ((CACHE_SIZE - 1) / sizeof(spanpackage_t)) + 1]; + // one extra because of cache line pretouching +// spanpackage_t *spans; +// spans = malloc( (sizeof(spanpackage_t) * (DPS_MAXSPANS+5))); + + a_spans = (spanpackage_t *) (((long)&spans[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + + if (r_affinetridesc.drawtype) + { + D_DrawSubdiv (); + } + else + { + D_DrawNonSubdiv (); + } + // free(spans); +} +#else +//JB: Optimization +//Dan East: May result in image quality loss. Actual performance gain not verified. +void D_PolysetDraw (void) +{ + spanpackage_t spans[DPS_MAXSPANS + 1 + + ((CACHE_SIZE - 1) / sizeof(spanpackage_t)) + 1]; + // one extra because of cache line pretouching +// spanpackage_t *spans; + +// spans = malloc( (sizeof(spanpackage_t) * (DPS_MAXSPANS+5))); + + a_spans = (spanpackage_t *) + (((long)&spans[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + + D_DrawNonSubdiv (); + + // free(spans); +} +#endif +/* +================ +D_PolysetDrawFinalVerts +================ +*/ +void D_PolysetDrawFinalVerts (finalvert_t *fv, int numverts) +{ + int i, z; + short *zbuf; + + for (i=0 ; iv[0] < r_refdef.vrectright) && + (fv->v[1] < r_refdef.vrectbottom)) + { + z = fv->v[5]>>16; + zbuf = zspantable[fv->v[1]] + fv->v[0]; + if (z >= *zbuf) + { + int pix; + + *zbuf = z; + pix = skintable[fv->v[3]>>16][fv->v[2]>>16]; + pix = ((byte *)acolormap)[pix + (fv->v[4] & 0xFF00) ]; + d_viewbuffer[d_scantable[fv->v[1]] + fv->v[0]] = pix; + } + } + } +} + + +/* +================ +D_DrawSubdiv +================ +*/ +int d_i; +finalvert_t *d_pfv, *d_index0, *d_index1, *d_index2; + +void D_DrawSubdiv (void) +{ + mtriangle_t *ptri; + finalvert_t *pfv, *index0, *index1, *index2; + int i; + int lnumtriangles; + + pfv = r_affinetridesc.pfinalverts; + ptri = r_affinetridesc.ptriangles; + lnumtriangles = r_affinetridesc.numtriangles; + + for (i=0 ; iv[1]-index1->v[1]) * + (index0->v[0]-index2->v[0]) - + (index0->v[0]-index1->v[0]) * + (index0->v[1]-index2->v[1])) >= 0) + { + continue; + } + + d_pcolormap = &((byte *)acolormap)[index0->v[4] & 0xFF00]; + + if (ptri[i].facesfront) + { + D_PolysetRecursiveTriangle(index0->v, index1->v, index2->v); + } + else + { + int s0, s1, s2; + + s0 = index0->v[2]; + s1 = index1->v[2]; + s2 = index2->v[2]; + + if (index0->flags & ALIAS_ONSEAM) + index0->v[2] += r_affinetridesc.seamfixupX16; + if (index1->flags & ALIAS_ONSEAM) + index1->v[2] += r_affinetridesc.seamfixupX16; + if (index2->flags & ALIAS_ONSEAM) + index2->v[2] += r_affinetridesc.seamfixupX16; + + D_PolysetRecursiveTriangle(index0->v, index1->v, index2->v); + + index0->v[2] = s0; + index1->v[2] = s1; + index2->v[2] = s2; + } + } +} + + +/* +================ +D_DrawNonSubdiv +================ +*/ +void D_DrawNonSubdiv (void) +{ + mtriangle_t *ptri; + finalvert_t *pfv, *index0, *index1, *index2; + int i; + int lnumtriangles; + + pfv = r_affinetridesc.pfinalverts; + ptri = r_affinetridesc.ptriangles; + lnumtriangles = r_affinetridesc.numtriangles; + + for (i=0 ; ivertindex[0]; + index1 = pfv + ptri->vertindex[1]; + index2 = pfv + ptri->vertindex[2]; + + d_xdenom = (index0->v[1]-index1->v[1]) * + (index0->v[0]-index2->v[0]) - + (index0->v[0]-index1->v[0])*(index0->v[1]-index2->v[1]); + + if (d_xdenom >= 0) + { + continue; + } + + r_p0[0] = index0->v[0]; // u + r_p0[1] = index0->v[1]; // v + r_p0[2] = index0->v[2]; // s + r_p0[3] = index0->v[3]; // t + r_p0[4] = index0->v[4]; // light + r_p0[5] = index0->v[5]; // iz + + r_p1[0] = index1->v[0]; + r_p1[1] = index1->v[1]; + r_p1[2] = index1->v[2]; + r_p1[3] = index1->v[3]; + r_p1[4] = index1->v[4]; + r_p1[5] = index1->v[5]; + + r_p2[0] = index2->v[0]; + r_p2[1] = index2->v[1]; + r_p2[2] = index2->v[2]; + r_p2[3] = index2->v[3]; + r_p2[4] = index2->v[4]; + r_p2[5] = index2->v[5]; + + if (!ptri->facesfront) + { + if (index0->flags & ALIAS_ONSEAM) + r_p0[2] += r_affinetridesc.seamfixupX16; + if (index1->flags & ALIAS_ONSEAM) + r_p1[2] += r_affinetridesc.seamfixupX16; + if (index2->flags & ALIAS_ONSEAM) + r_p2[2] += r_affinetridesc.seamfixupX16; + } + + D_PolysetSetEdgeTable (); + D_RasterizeAliasPolySmooth (); + } +} + + +/* +================ +D_PolysetRecursiveTriangle +================ +*/ +// Yoda +#pragma DISABLE_OPTIMIZATION +void D_PolysetRecursiveTriangle (int *lp1, int *lp2, int *lp3) +{ + int *temp; + int d; + int new[6]; + int z; + short *zbuf; + + d = lp2[0] - lp1[0]; + if (d < -1 || d > 1) + goto split; + d = lp2[1] - lp1[1]; + if (d < -1 || d > 1) + goto split; + + d = lp3[0] - lp2[0]; + if (d < -1 || d > 1) + goto split2; + d = lp3[1] - lp2[1]; + if (d < -1 || d > 1) + goto split2; + + d = lp1[0] - lp3[0]; + if (d < -1 || d > 1) + goto split3; + d = lp1[1] - lp3[1]; + if (d < -1 || d > 1) + { +split3: + temp = lp1; + lp1 = lp3; + lp3 = lp2; + lp2 = temp; + + goto split; + } + + return; // entire tri is filled + +split2: + temp = lp1; + lp1 = lp2; + lp2 = lp3; + lp3 = temp; + +split: +// split this edge + new[0] = (lp1[0] + lp2[0]) >> 1; + new[1] = (lp1[1] + lp2[1]) >> 1; + new[2] = (lp1[2] + lp2[2]) >> 1; + new[3] = (lp1[3] + lp2[3]) >> 1; + new[5] = (lp1[5] + lp2[5]) >> 1; + +// draw the point if splitting a leading edge + if (lp2[1] > lp1[1]) + goto nodraw; + if ((lp2[1] == lp1[1]) && (lp2[0] < lp1[0])) + goto nodraw; + + + z = new[5]>>16; + zbuf = zspantable[new[1]] + new[0]; + if (z >= *zbuf) + { + int pix; + + *zbuf = z; + pix = d_pcolormap[skintable[new[3]>>16][new[2]>>16]]; + d_viewbuffer[d_scantable[new[1]] + new[0]] = pix; + } + +nodraw: +// recursively continue + D_PolysetRecursiveTriangle (lp3, lp1, new); + D_PolysetRecursiveTriangle (lp3, new, lp2); +} +// Yoda +#pragma ENABLE_OPTIMIZATION + +#endif // !id386 + + +/* +================ +D_PolysetUpdateTables +================ +*/ +void D_PolysetUpdateTables (void) +{ + int i; + byte *s; + + if (r_affinetridesc.skinwidth != skinwidth || + r_affinetridesc.pskin != skinstart) + { + skinwidth = r_affinetridesc.skinwidth; + skinstart = r_affinetridesc.pskin; + s = skinstart; + for (i=0 ; ipdest = d_pdest; + d_pedgespanpackage->pz = d_pz; + d_pedgespanpackage->count = d_aspancount; + d_pedgespanpackage->ptex = d_ptex; + + d_pedgespanpackage->sfrac = d_sfrac; + d_pedgespanpackage->tfrac = d_tfrac; + + // FIXME: need to clamp l, s, t, at both ends? + d_pedgespanpackage->light = d_light; + d_pedgespanpackage->zi = d_zi; + + d_pedgespanpackage++; + + errorterm += erroradjustup; + if (errorterm >= 0) + { + d_pdest += d_pdestextrastep; + d_pz += d_pzextrastep; + d_aspancount += d_countextrastep; + d_ptex += d_ptexextrastep; + d_sfrac += d_sfracextrastep; + d_ptex += d_sfrac >> 16; + + d_sfrac &= 0xFFFF; + d_tfrac += d_tfracextrastep; + if (d_tfrac & 0x10000) + { + d_ptex += r_affinetridesc.skinwidth; + d_tfrac &= 0xFFFF; + } + d_light += d_lightextrastep; + d_zi += d_ziextrastep; + errorterm -= erroradjustdown; + } + else + { + d_pdest += d_pdestbasestep; + d_pz += d_pzbasestep; + d_aspancount += ubasestep; + d_ptex += d_ptexbasestep; + d_sfrac += d_sfracbasestep; + d_ptex += d_sfrac >> 16; + d_sfrac &= 0xFFFF; + d_tfrac += d_tfracbasestep; + if (d_tfrac & 0x10000) + { + d_ptex += r_affinetridesc.skinwidth; + d_tfrac &= 0xFFFF; + } + d_light += d_lightbasestep; + d_zi += d_zibasestep; + } + } while (--height); +} + +#endif // !id386 + + +/* +=================== +D_PolysetSetUpForLineScan +==================== +*/ +void D_PolysetSetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv, + fixed8_t endvertu, fixed8_t endvertv) +{ + double dm, dn; + int tm, tn; + adivtab_t *ptemp; + +// TODO: implement x86 version + + errorterm = -1; + + tm = endvertu - startvertu; + tn = endvertv - startvertv; + + if (((tm <= 16) && (tm >= -15)) && + ((tn <= 16) && (tn >= -15))) + { + ptemp = &adivtab[((tm+15) << 5) + (tn+15)]; + ubasestep = ptemp->quotient; + erroradjustup = ptemp->remainder; + erroradjustdown = tn; + } + else + { + dm = (double)tm; + dn = (double)tn; + + FloorDivMod (dm, dn, &ubasestep, &erroradjustup); + + erroradjustdown = (int)dn; + } +} + + +#if !id386 + +/* +================ +D_PolysetCalcGradients +================ +*/ + +#ifndef USE_PQ_OPT4 +void D_PolysetCalcGradients (int skinwidth) +{ + float xstepdenominv, ystepdenominv, t0, t1; + float p01_minus_p21, p11_minus_p21, p00_minus_p20, p10_minus_p20; + + p00_minus_p20 = (float)(r_p0[0] - r_p2[0]); + p01_minus_p21 = (float)(r_p0[1] - r_p2[1]); + p10_minus_p20 = (float)(r_p1[0] - r_p2[0]); + p11_minus_p21 = (float)(r_p1[1] - r_p2[1]); + xstepdenominv = (float)(1.0 / (float)d_xdenom); + ystepdenominv = -xstepdenominv; + + // ceil () for light so positive steps are exaggerated, negative steps + // diminished, pushing us away from underflow toward overflow. Underflow is + // very visible, overflow is very unlikely, because of ambient lighting + t0 = (float)(r_p0[4] - r_p2[4]); + t1 = (float)(r_p1[4] - r_p2[4]); + r_lstepx = (int)ceil((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv); + r_lstepy = (int)ceil((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv); + + t0 = (float)(r_p0[2] - r_p2[2]); + t1 = (float)(r_p1[2] - r_p2[2]); + r_sstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv); + r_sstepy = (int)((t1 * p00_minus_p20 - t0* p10_minus_p20) * ystepdenominv); + + t0 = (float)(r_p0[3] - r_p2[3]); + t1 = (float)(r_p1[3] - r_p2[3]); + r_tstepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv); + r_tstepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv); + + t0 = (float)(r_p0[5] - r_p2[5]); + t1 = (float)(r_p1[5] - r_p2[5]); + r_zistepx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv); + r_zistepy = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv); + + a_sstepxfrac = r_sstepx & 0xFFFF; + a_tstepxfrac = r_tstepx & 0xFFFF; + a_ststepxwhole = skinwidth * (r_tstepx >> 16) + (r_sstepx >> 16); +} +#else +void D_PolysetCalcGradients (int skinwidth) +{ + //Dan East: Fixed point conversion + int p01_minus_p21, p11_minus_p21, p00_minus_p20, p10_minus_p20, t0, t1; + int tmp, ydenom; + + //float xstepdenominv = (float)(1.0 / (float)d_xdenom); + //float ystepdenominv = -xstepdenominv; + //int checkx, checky; + + p00_minus_p20 = (r_p0[0] - r_p2[0]); + p01_minus_p21 = (r_p0[1] - r_p2[1]); + p10_minus_p20 = (r_p1[0] - r_p2[0]); + p11_minus_p21 = (r_p1[1] - r_p2[1]); + + //xstepdenominv = d_xdenom; + ydenom=-d_xdenom; + //ystepdenominv = -xstepdenominv; + + t0 = (r_p0[4] - r_p2[4]); + t1 = (r_p1[4] - r_p2[4]); + //TODO: Ceil has been removed + tmp=t1 * p01_minus_p21 - t0 * p11_minus_p21; + r_lstepx = tmp / d_xdenom; + if (tmp%d_xdenom) r_lstepx++; + + tmp=t1 * p00_minus_p20 - t0 * p10_minus_p20; + r_lstepy = tmp / ydenom; + if (tmp%ydenom) r_lstepy++; + /* + checkx = (int)ceil((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv); + checky = (int)ceil((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv); + if (checkx-r_lstepx>1||checkx-r_lstepx<-1) + r_lstepx=r_lstepx; + if (checky-r_lstepy>1||checky-r_lstepy<-1) + r_lstepy=r_lstepy; + */ + t0 = (r_p0[2] - r_p2[2]); + t1 = (r_p1[2] - r_p2[2]); + r_sstepx = (t1 * p01_minus_p21 - t0 * p11_minus_p21) / d_xdenom; + r_sstepy = (t1 * p00_minus_p20 - t0* p10_minus_p20) / ydenom; + /* + checkx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv); + checky = (int)((t1 * p00_minus_p20 - t0* p10_minus_p20) * ystepdenominv); + if (checkx-r_sstepx>1||checkx-r_sstepx<-1) + r_lstepx=r_lstepx; + if (checky-r_sstepy>1||checky-r_sstepy<-1) + r_lstepy=r_lstepy; + */ + + t0 = (r_p0[3] - r_p2[3]); + t1 = (r_p1[3] - r_p2[3]); + r_tstepx = (t1 * p01_minus_p21 - t0 * p11_minus_p21) / d_xdenom; + r_tstepy = (t1 * p00_minus_p20 - t0 * p10_minus_p20) / ydenom; + /* + checkx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv); + checky = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv); + if (checkx-r_tstepx>1||checkx-r_tstepx<-1) + r_lstepx=r_lstepx; + if (checky-r_tstepy>1||checky-r_tstepy<-1) + r_lstepy=r_lstepy; + */ + + t0 = (r_p0[5] - r_p2[5]); + t1 = (r_p1[5] - r_p2[5]); + r_zistepx = (t1 * p01_minus_p21 - t0 * p11_minus_p21) / d_xdenom; + r_zistepy = (t1 * p00_minus_p20 - t0 * p10_minus_p20) / ydenom; + /* + checkx = (int)((t1 * p01_minus_p21 - t0 * p11_minus_p21) * xstepdenominv); + checky = (int)((t1 * p00_minus_p20 - t0 * p10_minus_p20) * ystepdenominv); + if (checkx-r_zistepx>1||checkx-r_zistepx<-1) + r_lstepx=checkx; + if (checky-r_zistepy>1||checky-r_zistepy<-1) + r_lstepy=checky; + */ + + a_sstepxfrac = r_sstepx & 0xFFFF; + a_tstepxfrac = r_tstepx & 0xFFFF; + a_ststepxwhole = skinwidth * (r_tstepx >> 16) + (r_sstepx >> 16); +} +#endif +#endif // !id386 + + +#if 0 +byte gelmap[256]; +void InitGel (byte *palette) +{ + int i; + int r; + + for (i=0 ; i<256 ; i++) + { +// r = (palette[i*3]>>4); + r = (palette[i*3] + palette[i*3+1] + palette[i*3+2])/(16*3); + gelmap[i] = /* 64 */ 0 + r; + } +} +#endif + + +#if !id386 + +/* +================ +D_PolysetDrawSpans8 +================ +*/ +void D_PolysetDrawSpans8 (spanpackage_t *pspanpackage) +{ + int lcount; + byte *lpdest; + byte *lptex; + int lsfrac, ltfrac; + int llight; + int lzi; + short *lpz; + + do + { + lcount = d_aspancount - pspanpackage->count; + + errorterm += erroradjustup; + if (errorterm >= 0) + { + d_aspancount += d_countextrastep; + errorterm -= erroradjustdown; + } + else + { + d_aspancount += ubasestep; + } + + if (lcount) + { + lpdest = pspanpackage->pdest; + lptex = pspanpackage->ptex; + lpz = pspanpackage->pz; + lsfrac = pspanpackage->sfrac; + ltfrac = pspanpackage->tfrac; + llight = pspanpackage->light; + lzi = pspanpackage->zi; + + do + { + if ((lzi >> 16) >= *lpz) + { + *lpdest = ((byte *)acolormap)[*lptex + (llight & 0xFF00)]; +// gel mapping *lpdest = gelmap[*lpdest]; + *lpz = lzi >> 16; + } + lpdest++; + lzi += r_zistepx; + lpz++; + llight += r_lstepx; + lptex += a_ststepxwhole; + lsfrac += a_sstepxfrac; + lptex += lsfrac >> 16; + lsfrac &= 0xFFFF; + ltfrac += a_tstepxfrac; + if (ltfrac & 0x10000) + { + lptex += r_affinetridesc.skinwidth; + ltfrac &= 0xFFFF; + } + } while (--lcount); + } + + pspanpackage++; + } while (pspanpackage->count != -999999); +} +#endif // !id386 + + +/* +================ +D_PolysetFillSpans8 +================ +*/ +void D_PolysetFillSpans8 (spanpackage_t *pspanpackage) +{ + int color; + +// FIXME: do z buffering + + color = d_aflatcolor++; + + while (1) + { + int lcount; + byte *lpdest; + + lcount = pspanpackage->count; + + if (lcount == -1) + return; + + if (lcount) + { + lpdest = pspanpackage->pdest; + + do + { + *lpdest++ = color; + } while (--lcount); + } + + pspanpackage++; + } +} + +/* +================ +D_RasterizeAliasPolySmooth +================ +*/ +void D_RasterizeAliasPolySmooth (void) +{ + int initialleftheight, initialrightheight; + int *plefttop, *prighttop, *pleftbottom, *prightbottom; + int working_lstepx, originalcount; + + plefttop = pedgetable->pleftedgevert0; + prighttop = pedgetable->prightedgevert0; + + pleftbottom = pedgetable->pleftedgevert1; + prightbottom = pedgetable->prightedgevert1; + + initialleftheight = pleftbottom[1] - plefttop[1]; + initialrightheight = prightbottom[1] - prighttop[1]; + +// +// set the s, t, and light gradients, which are consistent across the triangle +// because being a triangle, things are affine +// + D_PolysetCalcGradients (r_affinetridesc.skinwidth); + +// +// rasterize the polygon +// + +// +// scan out the top (and possibly only) part of the left edge +// + d_pedgespanpackage = a_spans; + + ystart = plefttop[1]; + d_aspancount = plefttop[0] - prighttop[0]; + + d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) + + (plefttop[3] >> 16) * r_affinetridesc.skinwidth; +#if id386 + d_sfrac = (plefttop[2] & 0xFFFF) << 16; + d_tfrac = (plefttop[3] & 0xFFFF) << 16; +#else + d_sfrac = plefttop[2] & 0xFFFF; + d_tfrac = plefttop[3] & 0xFFFF; +#endif + d_light = plefttop[4]; + d_zi = plefttop[5]; + + d_pdest = (byte *)d_viewbuffer + + ystart * screenwidth + plefttop[0]; + d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0]; + + if (initialleftheight == 1) + { + d_pedgespanpackage->pdest = d_pdest; + d_pedgespanpackage->pz = d_pz; + d_pedgespanpackage->count = d_aspancount; + d_pedgespanpackage->ptex = d_ptex; + + d_pedgespanpackage->sfrac = d_sfrac; + d_pedgespanpackage->tfrac = d_tfrac; + + // FIXME: need to clamp l, s, t, at both ends? + d_pedgespanpackage->light = d_light; + d_pedgespanpackage->zi = d_zi; + + d_pedgespanpackage++; + } + else + { + D_PolysetSetUpForLineScan(plefttop[0], plefttop[1], + pleftbottom[0], pleftbottom[1]); + + #if id386 + d_pzbasestep = (d_zwidth + ubasestep) << 1; + d_pzextrastep = d_pzbasestep + 2; + #else + d_pzbasestep = d_zwidth + ubasestep; + d_pzextrastep = d_pzbasestep + 1; + #endif + + d_pdestbasestep = screenwidth + ubasestep; + d_pdestextrastep = d_pdestbasestep + 1; + + // TODO: can reuse partial expressions here + + // for negative steps in x along left edge, bias toward overflow rather than + // underflow (sort of turning the floor () we did in the gradient calcs into + // ceil (), but plus a little bit) + if (ubasestep < 0) + working_lstepx = r_lstepx - 1; + else + working_lstepx = r_lstepx; + + d_countextrastep = ubasestep + 1; + d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) + + ((r_tstepy + r_tstepx * ubasestep) >> 16) * + r_affinetridesc.skinwidth; + #if id386 + d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) << 16; + d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) << 16; + #else + d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF; + d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF; + #endif + d_lightbasestep = r_lstepy + working_lstepx * ubasestep; + d_zibasestep = r_zistepy + r_zistepx * ubasestep; + + d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) + + ((r_tstepy + r_tstepx * d_countextrastep) >> 16) * + r_affinetridesc.skinwidth; + #if id386 + d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) << 16; + d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) << 16; + #else + d_sfracextrastep = (r_sstepy + r_sstepx*d_countextrastep) & 0xFFFF; + d_tfracextrastep = (r_tstepy + r_tstepx*d_countextrastep) & 0xFFFF; + #endif + d_lightextrastep = d_lightbasestep + working_lstepx; + d_ziextrastep = d_zibasestep + r_zistepx; + + D_PolysetScanLeftEdge (initialleftheight); + } + +// +// scan out the bottom part of the left edge, if it exists +// + if (pedgetable->numleftedges == 2) + { + int height; + + plefttop = pleftbottom; + pleftbottom = pedgetable->pleftedgevert2; + + height = pleftbottom[1] - plefttop[1]; + +// TODO: make this a function; modularize this function in general + + ystart = plefttop[1]; + d_aspancount = plefttop[0] - prighttop[0]; + d_ptex = (byte *)r_affinetridesc.pskin + (plefttop[2] >> 16) + + (plefttop[3] >> 16) * r_affinetridesc.skinwidth; + d_sfrac = 0; + d_tfrac = 0; + d_light = plefttop[4]; + d_zi = plefttop[5]; + + d_pdest = (byte *)d_viewbuffer + ystart * screenwidth + plefttop[0]; + d_pz = d_pzbuffer + ystart * d_zwidth + plefttop[0]; + + if (height == 1) + { + d_pedgespanpackage->pdest = d_pdest; + d_pedgespanpackage->pz = d_pz; + d_pedgespanpackage->count = d_aspancount; + d_pedgespanpackage->ptex = d_ptex; + + d_pedgespanpackage->sfrac = d_sfrac; + d_pedgespanpackage->tfrac = d_tfrac; + + // FIXME: need to clamp l, s, t, at both ends? + d_pedgespanpackage->light = d_light; + d_pedgespanpackage->zi = d_zi; + + d_pedgespanpackage++; + } + else + { + D_PolysetSetUpForLineScan(plefttop[0], plefttop[1], + pleftbottom[0], pleftbottom[1]); + + d_pdestbasestep = screenwidth + ubasestep; + d_pdestextrastep = d_pdestbasestep + 1; + + #if id386 + d_pzbasestep = (d_zwidth + ubasestep) << 1; + d_pzextrastep = d_pzbasestep + 2; + #else + d_pzbasestep = d_zwidth + ubasestep; + d_pzextrastep = d_pzbasestep + 1; + #endif + + if (ubasestep < 0) + working_lstepx = r_lstepx - 1; + else + working_lstepx = r_lstepx; + + d_countextrastep = ubasestep + 1; + d_ptexbasestep = ((r_sstepy + r_sstepx * ubasestep) >> 16) + + ((r_tstepy + r_tstepx * ubasestep) >> 16) * + r_affinetridesc.skinwidth; + #if id386 + d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) << 16; + d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) << 16; + #else + d_sfracbasestep = (r_sstepy + r_sstepx * ubasestep) & 0xFFFF; + d_tfracbasestep = (r_tstepy + r_tstepx * ubasestep) & 0xFFFF; + #endif + d_lightbasestep = r_lstepy + working_lstepx * ubasestep; + d_zibasestep = r_zistepy + r_zistepx * ubasestep; + + d_ptexextrastep = ((r_sstepy + r_sstepx * d_countextrastep) >> 16) + + ((r_tstepy + r_tstepx * d_countextrastep) >> 16) * + r_affinetridesc.skinwidth; + #if id386 + d_sfracextrastep = ((r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF)<<16; + d_tfracextrastep = ((r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF)<<16; + #else + d_sfracextrastep = (r_sstepy+r_sstepx*d_countextrastep) & 0xFFFF; + d_tfracextrastep = (r_tstepy+r_tstepx*d_countextrastep) & 0xFFFF; + #endif + d_lightextrastep = d_lightbasestep + working_lstepx; + d_ziextrastep = d_zibasestep + r_zistepx; + + D_PolysetScanLeftEdge (height); + } + } + +// scan out the top (and possibly only) part of the right edge, updating the +// count field + d_pedgespanpackage = a_spans; + + D_PolysetSetUpForLineScan(prighttop[0], prighttop[1], + prightbottom[0], prightbottom[1]); + d_aspancount = 0; + d_countextrastep = ubasestep + 1; + originalcount = a_spans[initialrightheight].count; + a_spans[initialrightheight].count = -999999; // mark end of the spanpackages + D_PolysetDrawSpans8 (a_spans); + +// scan out the bottom part of the right edge, if it exists + if (pedgetable->numrightedges == 2) + { + int height; + spanpackage_t *pstart; + + pstart = a_spans + initialrightheight; + pstart->count = originalcount; + + d_aspancount = prightbottom[0] - prighttop[0]; + + prighttop = prightbottom; + prightbottom = pedgetable->prightedgevert2; + + height = prightbottom[1] - prighttop[1]; + + D_PolysetSetUpForLineScan(prighttop[0], prighttop[1], + prightbottom[0], prightbottom[1]); + + d_countextrastep = ubasestep + 1; + a_spans[initialrightheight + height].count = -999999; + // mark end of the spanpackages + D_PolysetDrawSpans8 (pstart); + } +} + + +/* +================ +D_PolysetSetEdgeTable +================ +*/ +void D_PolysetSetEdgeTable (void) +{ + int edgetableindex; + + edgetableindex = 0; // assume the vertices are already in + // top to bottom order + +// +// determine which edges are right & left, and the order in which +// to rasterize them +// + if (r_p0[1] >= r_p1[1]) + { + if (r_p0[1] == r_p1[1]) + { + if (r_p0[1] < r_p2[1]) + pedgetable = &edgetables[2]; + else + pedgetable = &edgetables[5]; + + return; + } + else + { + edgetableindex = 1; + } + } + + if (r_p0[1] == r_p2[1]) + { + if (edgetableindex) + pedgetable = &edgetables[8]; + else + pedgetable = &edgetables[9]; + + return; + } + else if (r_p1[1] == r_p2[1]) + { + if (edgetableindex) + pedgetable = &edgetables[10]; + else + pedgetable = &edgetables[11]; + + return; + } + + if (r_p0[1] > r_p2[1]) + edgetableindex += 2; + + if (r_p1[1] > r_p2[1]) + edgetableindex += 4; + + pedgetable = &edgetables[edgetableindex]; +} + + +#if 0 + +void D_PolysetRecursiveDrawLine (int *lp1, int *lp2) +{ + int d; + int new[6]; + int ofs; + + d = lp2[0] - lp1[0]; + if (d < -1 || d > 1) + goto split; + d = lp2[1] - lp1[1]; + if (d < -1 || d > 1) + goto split; + + return; // line is completed + +split: +// split this edge + new[0] = (lp1[0] + lp2[0]) >> 1; + new[1] = (lp1[1] + lp2[1]) >> 1; + new[5] = (lp1[5] + lp2[5]) >> 1; + new[2] = (lp1[2] + lp2[2]) >> 1; + new[3] = (lp1[3] + lp2[3]) >> 1; + new[4] = (lp1[4] + lp2[4]) >> 1; + +// draw the point + ofs = d_scantable[new[1]] + new[0]; + if (new[5] > d_pzbuffer[ofs]) + { + int pix; + + d_pzbuffer[ofs] = new[5]; + pix = skintable[new[3]>>16][new[2]>>16]; +// pix = ((byte *)acolormap)[pix + (new[4] & 0xFF00)]; + d_viewbuffer[ofs] = pix; + } + +// recursively continue + D_PolysetRecursiveDrawLine (lp1, new); + D_PolysetRecursiveDrawLine (new, lp2); +} + +void D_PolysetRecursiveTriangle2 (int *lp1, int *lp2, int *lp3) +{ + int d; + int new[4]; + + d = lp2[0] - lp1[0]; + if (d < -1 || d > 1) + goto split; + d = lp2[1] - lp1[1]; + if (d < -1 || d > 1) + goto split; + return; + +split: +// split this edge + new[0] = (lp1[0] + lp2[0]) >> 1; + new[1] = (lp1[1] + lp2[1]) >> 1; + new[5] = (lp1[5] + lp2[5]) >> 1; + new[2] = (lp1[2] + lp2[2]) >> 1; + new[3] = (lp1[3] + lp2[3]) >> 1; + new[4] = (lp1[4] + lp2[4]) >> 1; + + D_PolysetRecursiveDrawLine (new, lp3); + +// recursively continue + D_PolysetRecursiveTriangle (lp1, new, lp3); + D_PolysetRecursiveTriangle (new, lp2, lp3); +} + +#endif + diff --git a/project/jni/application/quake/source/d_scan.c b/project/jni/application/quake/source/d_scan.c new file mode 100644 index 000000000..e8e82b4ee --- /dev/null +++ b/project/jni/application/quake/source/d_scan.c @@ -0,0 +1,594 @@ +// d_scan.c +// Portable C scan-level rasterization code, all pixel depths. +#include "quakedef.h" +#include "r_local.h" +#include "d_local.h" + +unsigned char *r_turb_pbase, *r_turb_pdest; +fixed16_t r_turb_s, r_turb_t, r_turb_sstep, r_turb_tstep; +int *r_turb_turb; +int r_turb_spancount; + +void D_DrawTurbulent8Span (void); + +/*============================================== +// D_WarpScreen +// this performs a slight compression of the screen at the same time as +// the sine warp, to keep the edges from wrapping +//============================================*/ +void D_WarpScreen (void) +{ + int w, h; + int u,v; + byte *dest; + int *turb; + int *col; + byte **row; + byte *rowptr[MAXHEIGHT+(AMP2*2)]; + int column[MAXWIDTH+(AMP2*2)]; + float wratio, hratio; + w = r_refdef.vrect.width; + h = r_refdef.vrect.height; + wratio = w / (float)scr_vrect.width; + hratio = h / (float)scr_vrect.height; + for (v=0 ; v>16)&(CYCLE-1)])>>16)&63; + tturb = ((r_turb_t + r_turb_turb[(r_turb_s>>16)&(CYCLE-1)])>>16)&63; + *r_turb_pdest++ = *(r_turb_pbase + (tturb<<6) + sturb); + r_turb_s += r_turb_sstep; + r_turb_t += r_turb_tstep; + } while (--r_turb_spancount > 0); +} + +#endif // !id386 + +/*============================================== +// Turbulent8 +//============================================*/ +void Turbulent8 (espan_t *pspan) +{ + int count; + fixed16_t snext, tnext; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz16stepu, tdivz16stepu, zi16stepu; + r_turb_turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1)); + r_turb_sstep = 0; // keep compiler happy + r_turb_tstep = 0; // ditto + r_turb_pbase = (unsigned char *)cacheblock; + sdivz16stepu = d_sdivzstepu * 16; + tdivz16stepu = d_tdivzstepu * 16; + zi16stepu = d_zistepu * 16; + do + { + r_turb_pdest = (unsigned char *)((byte *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + count = pspan->count; + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + r_turb_s = (int)(sdivz * z) + sadjust; + if (r_turb_s > bbextents) r_turb_s = bbextents; + else if (r_turb_s < 0) r_turb_s = 0; + r_turb_t = (int)(tdivz * z) + tadjust; + if (r_turb_t > bbextentt) r_turb_t = bbextentt; + else if (r_turb_t < 0) r_turb_t = 0; + do + { + // calculate s and t at the far end of the span + if (count >= 16) r_turb_spancount = 16; + else r_turb_spancount = count; + count -= r_turb_spancount; + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz16stepu; + tdivz += tdivz16stepu; + zi += zi16stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) snext = bbextents; + else if (snext < 16) snext = 16; + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) tnext = bbextentt; + else if (tnext < 16) tnext = 16; // guard against round-off error on <0 steps + r_turb_sstep = (snext - r_turb_s) >> 4; + r_turb_tstep = (tnext - r_turb_t) >> 4; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(r_turb_spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) snext = bbextents; + else if (snext < 16) snext = 16; + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) tnext = bbextentt; + else if (tnext < 16) tnext = 16; // guard against round-off error on <0 steps + if (r_turb_spancount > 1) + { + r_turb_sstep = (snext - r_turb_s) / (r_turb_spancount - 1); + r_turb_tstep = (tnext - r_turb_t) / (r_turb_spancount - 1); + } + } + r_turb_s = r_turb_s & ((CYCLE<<16)-1); + r_turb_t = r_turb_t & ((CYCLE<<16)-1); + D_DrawTurbulent8Span (); + r_turb_s = snext; + r_turb_t = tnext; + } while (count > 0); + } while ((pspan = pspan->pnext) != NULL); +} + +#if !id386 + + +/*============================================== +// D_DrawSpans8 +//============================================*/ +#ifndef USE_PQ_OPT5 +void D_DrawSpans8 (espan_t *pspan) +{ + int count, spancount; + unsigned char *pbase, *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz8stepu, tdivz8stepu, zi8stepu; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + pbase = (unsigned char *)cacheblock; + + sdivz8stepu = d_sdivzstepu * 8; + tdivz8stepu = d_tdivzstepu * 8; + zi8stepu = d_zistepu * 8; + + do + { + pdest = (unsigned char *)((byte *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + s = (int)(sdivz * z) + sadjust; + if (s > bbextents) + s = bbextents; + else if (s < 0) + s = 0; + + t = (int)(tdivz * z) + tadjust; + if (t > bbextentt) + t = bbextentt; + else if (t < 0) + t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 8) + spancount = 8; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + sstep = (snext - s) >> 3; + tstep = (tnext - t) >> 3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = (snext - s) / (spancount - 1); + tstep = (tnext - t) / (spancount - 1); + } + } + + do + { + *pdest++ = *(pbase + (s >> 16) + (t >> 16) * cachewidth); + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} +#else + +static int sdivzorig, sdivzstepv, sdivzstepu, sdivz8stepu; +static int tdivzorig, tdivzstepv, tdivzstepu, tdivz8stepu; +static int zi8stepu; +static float last = 0; + +/*============================================== +// UpdateFixedPointVars +//============================================*/ +void UpdateFixedPointVars( int all ) +{ + // JB: Store texture transformation matrix in fixed point vars + if (all) + { +/* + sdivzorig = (int)(524288.0f * d_sdivzorigin); // 13.19 fixed point + tdivzorig = (int)(524288.0f * d_tdivzorigin); + sdivzstepv = (int)(524288.0f * d_sdivzstepv); + tdivzstepv = (int)(524288.0f * d_tdivzstepv); + sdivzstepu = (int)(524288.0f * d_sdivzstepu); + sdivz8stepu = sdivzstepu*8; + tdivzstepu = (int)(524288.0f * d_tdivzstepu); + tdivz8stepu = tdivzstepu*8; +*/ + + sdivzorig = (int)(4194304.0f * d_sdivzorigin); // 10.22 fixed point + tdivzorig = (int)(4194304.0f * d_tdivzorigin); + sdivzstepv = (int)(4194304.0f * d_sdivzstepv); + tdivzstepv = (int)(4194304.0f * d_tdivzstepv); + sdivzstepu = (int)(4194304.0f * d_sdivzstepu); + sdivz8stepu = sdivzstepu*8; + tdivzstepu = (int)(4194304.0f * d_tdivzstepu); + tdivz8stepu = tdivzstepu*8; + + } +/* + ziorig = (int)(524288.0f * d_ziorigin); // 13.19 fixed point + zistepv = (int)(524288.0f * d_zistepv ); + zistepu = (int)(524288.0f * d_zistepu ); +*/ +#ifndef USE_PQ_OPT3 + d_ziorigin_fxp = (int)(4194304.0f * d_ziorigin); // 10.22 fixed point + d_zistepv_fxp = (int)(4194304.0f * d_zistepv ); + d_zistepu_fxp = (int)(4194304.0f * d_zistepu ); +#endif + + zi8stepu = d_zistepu_fxp * 8; + last = d_zistepv; +} + +void D_DrawSpans8 (espan_t *pspan) +{ + int count, spancount, spancountminus1; + unsigned char *pbase, *pdest; + fixed16_t s1, t1; + int zi, sdivz, tdivz, sstep, tstep; + int snext, tnext; + pbase = (unsigned char *)cacheblock; + //Jacco Biker's fixed point conversion + + // Recalc fixed point values + UpdateFixedPointVars( 1 ); + do + { + pdest = (unsigned char *)((byte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u); + count = pspan->count; + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + sdivz = sdivzorig + pspan->v * sdivzstepv + pspan->u * sdivzstepu; + tdivz = tdivzorig + pspan->v * tdivzstepv + pspan->u * tdivzstepu; + zi = d_ziorigin_fxp + pspan->v * d_zistepv_fxp + pspan->u * d_zistepu_fxp; + if (zi == 0) zi = 1; + s1 = (((sdivz << 8) / zi) << 8) + sadjust; // 5.27 / 13.19 = 24.8 >> 8 = 16.16 + if (s1 > bbextents) s1 = bbextents; else if (s1 < 0) s1 = 0; + t1 = (((tdivz << 8) / zi) << 8) + tadjust; + if (t1 > bbextentt) t1 = bbextentt; else if (t1 < 0) t1 = 0; + // calculate final s/z, t/z, 1/z, s, and t and clamp + //sdivz += sdivzstepu * (count - 1); + //tdivz += tdivzstepu * (count - 1); + //zi += d_zistepu_fxp * (count - 1); + //if (zi == 0) zi = 1; +#if 0 + s2 = (((sdivz << 8) / zi) << 8) + sadjust; + if (s2 > bbextents) s2 = bbextents; else if (s2 < 8) s2 = 8; + t2 = (((tdivz << 8) / zi) << 8) + tadjust; + if (t2 > bbextentt) t2 = bbextentt; else if (t2 < 8) t2 = 8; + if (count > 1) + { + sstep = (s2 - s1) / (count - 1); + tstep = (t2 - t1) / (count - 1); + } +#else + //End Jacco Biker mod + //Dan East: Fixed point conversion for perspective correction + do + { + // calculate s and t at the far end of the span + if (count >= 8) + spancount = 8; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + if (!zi) zi = 1; + //z = zi; + //z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (((sdivz<<8)/zi)<<8)+sadjust; + //snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (((tdivz<<8)/zi)<<8) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + sstep = (snext - s1) >> 3; + tstep = (tnext - t1) >> 3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = spancount - 1; + sdivz += sdivzstepu * spancountminus1; + tdivz += tdivzstepu * spancountminus1; + zi += d_zistepu_fxp * spancountminus1; + if (!zi) zi = 1; + //z = zi;//(float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (((sdivz<<8) / zi)<<8) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (((tdivz<<8) / zi)<<8) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = ((snext - s1)) / ((spancount - 1)); + tstep = ((tnext - t1)) / ((spancount - 1)); + } + } + do + { + *pdest++ = *(pbase + (s1 >> 16) + (t1 >> 16) * cachewidth); + s1 += sstep; + t1 += tstep; + } while (--spancount > 0); + + s1 = snext; + t1 = tnext; + + } while (count > 0); +#endif +#if 0 + // Draw span + for ( i = 0; i < count; i++ ) + { + *pdest++ = *(pbase + (s1 >> 16) + (t1 >> 16) * cachewidth); + s1 += sstep; + t1 += tstep; + } +#endif + } while ((pspan = pspan->pnext) != NULL); +} + +#endif +#endif //USE_PQ_OPT5 + +#ifdef USE_PQ_OPT5 +#if !id386 +/*============================================== +// D_DrawZSpans +//============================================*/ +void D_DrawZSpans (espan_t *pspan) +{ + int count, doublecount, izistep; + int izi; + short *pdest; + unsigned ltemp; +#ifdef USE_PQ_OPT5 + // Recalc fixed point values + UpdateFixedPointVars( 0 ); +#endif + izistep = d_zistepu_fxp << 9; + do + { + pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u; + count = pspan->count; + // calculate the initial 1/z + izi = (d_ziorigin_fxp + pspan->v * d_zistepv_fxp + pspan->u * d_zistepu_fxp) << 9; // 1.31 fixed point + if ((long)pdest & 0x02) + { + *pdest++ = (short)(izi >> 16); + izi += izistep; + count--; + } + if ((doublecount = count >> 1) > 0) + { + do + { + ltemp = izi >> 16; + izi += izistep; + ltemp |= izi & 0xFFFF0000; + izi += izistep; + *(int *)pdest = ltemp; + pdest += 2; + } while (--doublecount > 0); + } + if (count & 1) *pdest = (short)(izi >> 16); + + } while ((pspan = pspan->pnext) != NULL); +} +#endif +#else +void D_DrawZSpans (espan_t *pspan) +{ + int count, doublecount, izistep; + int izi; + short *pdest; + unsigned ltemp; + double zi; + float du, dv; + + +// FIXME: check for clamping/range problems +// we count on FP exceptions being turned off to avoid range problems + izistep = (int)(d_zistepu * 0x8000 * 0x10000); + + do + { + pdest = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u; + + count = pspan->count; + + // calculate the initial 1/z + du = (float)pspan->u; + dv = (float)pspan->v; + + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + // we count on FP exceptions being turned off to avoid range problems + izi = (int)(zi * 0x8000 * 0x10000); + + if ((long)pdest & 0x02) + { + *pdest++ = (short)(izi >> 16); + izi += izistep; + count--; + } + + if ((doublecount = count >> 1) > 0) + { + do + { + ltemp = izi >> 16; + izi += izistep; + ltemp |= izi & 0xFFFF0000; + izi += izistep; + *(int *)pdest = ltemp; + pdest += 2; + } while (--doublecount > 0); + } + + if (count & 1) + *pdest = (short)(izi >> 16); + + } while ((pspan = pspan->pnext) != NULL); +} + +#endif diff --git a/project/jni/application/quake/source/d_sky.c b/project/jni/application/quake/source/d_sky.c new file mode 100644 index 000000000..954ce9bd3 --- /dev/null +++ b/project/jni/application/quake/source/d_sky.c @@ -0,0 +1,207 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_sky.c + +#include "quakedef.h" +#include "r_local.h" +#include "d_local.h" + +#define SKY_SPAN_SHIFT 5 +#define SKY_SPAN_MAX (1 << SKY_SPAN_SHIFT) + + +/* +================= +D_Sky_uv_To_st +================= +*/ +void D_Sky_uv_To_st (int u, int v, fixed16_t *s, fixed16_t *t) +{ + float wu, wv, temp; + vec3_t end; + + if (r_refdef.vrect.width >= r_refdef.vrect.height) + temp = (float)r_refdef.vrect.width; + else + temp = (float)r_refdef.vrect.height; + + wu = (float)(8192.0 * (float)(u-((int)vid.width>>1)) / temp); + wv = (float)(8192.0 * (float)(((int)vid.height>>1)-v) / temp); + + end[0] = 4096*vpn[0] + wu*vright[0] + wv*vup[0]; + end[1] = 4096*vpn[1] + wu*vright[1] + wv*vup[1]; + end[2] = 4096*vpn[2] + wu*vright[2] + wv*vup[2]; + end[2] *= 3; + VectorNormalize (end); + + temp = skytime*skyspeed; // TODO: add D_SetupFrame & set this there + *s = (int)((temp + 6*(SKYSIZE/2-1)*end[0]) * 0x10000); + *t = (int)((temp + 6*(SKYSIZE/2-1)*end[1]) * 0x10000); +} + +#ifdef USEFPM +void D_Sky_uv_To_stFPM (int u, int v, fixed16_t *s, fixed16_t *t) +{ + fixedpoint_t wu, wv, temp; + vec3_FPM_t end; + + if (r_refdefFPM.vrect.width >= r_refdefFPM.vrect.height) + temp = FPM_FROMLONG(r_refdefFPM.vrect.width); + else + temp = FPM_FROMLONG(r_refdefFPM.vrect.height); + + wu = FPM_DIV(FPM_MUL(FPM_FROMFLOAT(8192.0), FPM_FROMLONG(u-(vid.width>>1))), temp); + wv = FPM_DIV(FPM_MUL(FPM_FROMFLOAT(8192.0), FPM_FROMLONG(((int)vid.height>>1)-v)), temp); + + end[0] = FPM_ADD3(FPM_MUL(FPM_FROMLONG(4096),vpnFPM[0]), FPM_MUL(wu,vrightFPM[0]), FPM_MUL(wv,vupFPM[0])); + end[1] = FPM_ADD3(FPM_MUL(FPM_FROMLONG(4096),vpnFPM[1]), FPM_MUL(wu,vrightFPM[1]), FPM_MUL(wv,vupFPM[1])); + end[2] = FPM_ADD3(FPM_MUL(FPM_FROMLONG(4096),vpnFPM[2]), FPM_MUL(wu,vrightFPM[2]), FPM_MUL(wv,vupFPM[2])); + end[2] = FPM_MUL(end[2], FPM_FROMLONG(3)); + VectorNormalizeFPM (end); + + temp = FPM_MUL(FPM_FROMFLOAT(skytime),FPM_FROMFLOAT(skyspeed)); // TODO: add D_SetupFrame & set this there + *s = FPM_ADD(temp, FPM_MUL(FPM_FROMLONG(6*(SKYSIZE/2-1)),end[0]));// * 0x10000); + *t = FPM_ADD(temp, FPM_MUL(FPM_FROMLONG(6*(SKYSIZE/2-1)),end[1]));// * 0x10000); +} +#endif + +/* +================= +D_DrawSkyScans8 +================= +*/ +#ifndef USE_PQ_OPT +void D_DrawSkyScans8 (espan_t *pspan) +{ + int count, spancount, u, v; + unsigned char *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + int spancountminus1; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + do + { + pdest = (unsigned char *)((byte *)d_viewbuffer + + (screenwidth * pspan->v) + pspan->u); + + count = pspan->count; + + // calculate the initial s & t + u = pspan->u; + v = pspan->v; + D_Sky_uv_To_st (u, v, &s, &t); + + do + { + if (count >= SKY_SPAN_MAX) + spancount = SKY_SPAN_MAX; + else + spancount = count; + + count -= spancount; + + if (count) + { + u += spancount; + + // calculate s and t at far end of span, + // calculate s and t steps across span by shifting + D_Sky_uv_To_st (u, v, &snext, &tnext); + + sstep = (snext - s) >> SKY_SPAN_SHIFT; + tstep = (tnext - t) >> SKY_SPAN_SHIFT; + } + else + { + // calculate s and t at last pixel in span, + // calculate s and t steps across span by division + //Dan: I don't know why they were casting this to a float?? I removed the cast. + spancountminus1 = /*(float)*/(spancount - 1); + + if (spancountminus1 > 0) + { + u += spancountminus1; + D_Sky_uv_To_st (u, v, &snext, &tnext); + + sstep = (snext - s) / spancountminus1; + tstep = (tnext - t) / spancountminus1; + } + } + + do + { + *pdest++ = r_skysource[((t & R_SKY_TMASK) >> 8) + + ((s & R_SKY_SMASK) >> 16)]; + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + + } while ((pspan = pspan->pnext) != NULL); +} +#else +//JB: Optimization +//Dan East: Will result in sky image distortion (although possibly not noticeable). +void D_DrawSkyScans8 (espan_t *pspan) +{ + int count, spancount, u, v; + unsigned char *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + int spancountminus1; + sstep = 0; // keep compiler happy + tstep = 0; // ditto + do + { + pdest = (unsigned char *)((byte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u); + count = pspan->count; + // calculate the initial s & t + u = pspan->u; + v = pspan->v; + D_Sky_uv_To_st (u, v, &s, &t); + spancount = count; + count -= spancount; + // calculate s and t at last pixel in span, + // calculate s and t steps across span by division + spancountminus1 = /*(float)*/(spancount - 1); + if (spancountminus1 > 0) + { + u += spancountminus1; + D_Sky_uv_To_st (u, v, &snext, &tnext); + sstep = (snext - s) / spancountminus1; + tstep = (tnext - t) / spancountminus1; + } + do + { + *pdest++ = r_skysource[((t & R_SKY_TMASK) >> 8) + + ((s & R_SKY_SMASK) >> 16)]; + s += sstep; + t += tstep; + } while (--spancount > 0); + s = snext; + t = tnext; + } while ((pspan = pspan->pnext) != NULL); +} +#endif diff --git a/project/jni/application/quake/source/d_sprite.c b/project/jni/application/quake/source/d_sprite.c new file mode 100644 index 000000000..768da4ae5 --- /dev/null +++ b/project/jni/application/quake/source/d_sprite.c @@ -0,0 +1,839 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_sprite.c: software top-level rasterization driver module for drawing +// sprites + +#include "quakedef.h" +#include "d_local.h" + +static int sprite_height; +static int minindex, maxindex; +static sspan_t *sprite_spans; + +#if !id386 + +/* +===================== +D_SpriteDrawSpans +===================== +*/ +void D_SpriteDrawSpans (sspan_t *pspan) +{ + int count, spancount, izistep; + int izi; + byte *pbase, *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz8stepu, tdivz8stepu, zi8stepu; + byte btemp; + short *pz; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + pbase = cacheblock; + + sdivz8stepu = d_sdivzstepu * 8; + tdivz8stepu = d_tdivzstepu * 8; + zi8stepu = d_zistepu * 8; + +// we count on FP exceptions being turned off to avoid range problems + izistep = (int)(d_zistepu * 0x8000 * 0x10000); + + do + { + pdest = (byte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u; + pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u; + + count = pspan->count; + + if (count <= 0) + goto NextSpan; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + // we count on FP exceptions being turned off to avoid range problems + izi = (int)(zi * 0x8000 * 0x10000); + + s = (int)(sdivz * z) + sadjust; + if (s > bbextents) + s = bbextents; + else if (s < 0) + s = 0; + + t = (int)(tdivz * z) + tadjust; + if (t > bbextentt) + t = bbextentt; + else if (t < 0) + t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 8) + spancount = 8; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + sstep = (snext - s) >> 3; + tstep = (tnext - t) >> 3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = (snext - s) / (spancount - 1); + tstep = (tnext - t) / (spancount - 1); + } + } + + do + { + btemp = *(pbase + (s >> 16) + (t >> 16) * cachewidth); + if (btemp != 255) + { + if (*pz <= (izi >> 16)) + { + *pz = izi >> 16; + *pdest = btemp; + } + } + + izi += izistep; + pdest++; + pz++; + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + +NextSpan: + pspan++; + + } while (pspan->count != DS_SPAN_LIST_END); +} + +#ifdef USEFPM +void D_SpriteDrawSpansFPM (sspan_t *pspan) +{ + //Dan: Sprite routines not yet converted to fixed point +/* + int count, spancount, izistep; + int izi; + byte *pbase, *pdest; + fixed16_t s, t, snext, tnext, sstep, tstep; + float sdivz, tdivz, zi, z, du, dv, spancountminus1; + float sdivz8stepu, tdivz8stepu, zi8stepu; + byte btemp; + short *pz; + + sstep = 0; // keep compiler happy + tstep = 0; // ditto + + pbase = cacheblock; + + sdivz8stepu = d_sdivzstepu * 8; + tdivz8stepu = d_tdivzstepu * 8; + zi8stepu = d_zistepu * 8; + +// we count on FP exceptions being turned off to avoid range problems + izistep = (int)(d_zistepu * 0x8000 * 0x10000); + + do + { + pdest = (byte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u; + pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u; + + count = pspan->count; + + if (count <= 0) + goto NextSpan; + + // calculate the initial s/z, t/z, 1/z, s, and t and clamp + du = (float)pspan->u; + dv = (float)pspan->v; + + sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu; + tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu; + zi = d_ziorigin + dv*d_zistepv + du*d_zistepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + // we count on FP exceptions being turned off to avoid range problems + izi = (int)(zi * 0x8000 * 0x10000); + + s = (int)(sdivz * z) + sadjust; + if (s > bbextents) + s = bbextents; + else if (s < 0) + s = 0; + + t = (int)(tdivz * z) + tadjust; + if (t > bbextentt) + t = bbextentt; + else if (t < 0) + t = 0; + + do + { + // calculate s and t at the far end of the span + if (count >= 8) + spancount = 8; + else + spancount = count; + + count -= spancount; + + if (count) + { + // calculate s/z, t/z, zi->fixed s and t at far end of span, + // calculate s and t steps across span by shifting + sdivz += sdivz8stepu; + tdivz += tdivz8stepu; + zi += zi8stepu; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + sstep = (snext - s) >> 3; + tstep = (tnext - t) >> 3; + } + else + { + // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so + // can't step off polygon), clamp, calculate s and t steps across + // span by division, biasing steps low so we don't run off the + // texture + spancountminus1 = (float)(spancount - 1); + sdivz += d_sdivzstepu * spancountminus1; + tdivz += d_tdivzstepu * spancountminus1; + zi += d_zistepu * spancountminus1; + z = (float)0x10000 / zi; // prescale to 16.16 fixed-point + snext = (int)(sdivz * z) + sadjust; + if (snext > bbextents) + snext = bbextents; + else if (snext < 8) + snext = 8; // prevent round-off error on <0 steps from + // from causing overstepping & running off the + // edge of the texture + + tnext = (int)(tdivz * z) + tadjust; + if (tnext > bbextentt) + tnext = bbextentt; + else if (tnext < 8) + tnext = 8; // guard against round-off error on <0 steps + + if (spancount > 1) + { + sstep = (snext - s) / (spancount - 1); + tstep = (tnext - t) / (spancount - 1); + } + } + + do + { + btemp = *(pbase + (s >> 16) + (t >> 16) * cachewidth); + if (btemp != 255) + { + if (*pz <= (izi >> 16)) + { + *pz = izi >> 16; + *pdest = btemp; + } + } + + izi += izistep; + pdest++; + pz++; + s += sstep; + t += tstep; + } while (--spancount > 0); + + s = snext; + t = tnext; + + } while (count > 0); + +NextSpan: + pspan++; + + } while (pspan->count != DS_SPAN_LIST_END); + */ +} +#endif +#endif + + +/* +===================== +D_SpriteScanLeftEdge +===================== +*/ +void D_SpriteScanLeftEdge (void) +{ + int i, v, itop, ibottom, lmaxindex; + emitpoint_t *pvert, *pnext; + sspan_t *pspan; + float du, dv, vtop, vbottom, slope; + fixed16_t u, u_step; + + pspan = sprite_spans; + i = minindex; + if (i == 0) + i = r_spritedesc.nump; + + lmaxindex = maxindex; + if (lmaxindex == 0) + lmaxindex = r_spritedesc.nump; + + vtop = (float)ceil (r_spritedesc.pverts[i].v); + + do + { + pvert = &r_spritedesc.pverts[i]; + pnext = pvert - 1; + + vbottom = (float)ceil (pnext->v); + + if (vtop < vbottom) + { + du = pnext->u - pvert->u; + dv = pnext->v - pvert->v; + slope = du / dv; + u_step = (int)(slope * 0x10000); + // adjust u to ceil the integer portion + u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) + + (0x10000 - 1); + itop = (int)vtop; + ibottom = (int)vbottom; + + for (v=itop ; vu = u >> 16; + pspan->v = v; + u += u_step; + pspan++; + } + } + + vtop = vbottom; + + i--; + if (i == 0) + i = r_spritedesc.nump; + + } while (i != lmaxindex); +} + +#ifdef USEFPM +void D_SpriteScanLeftEdgeFPM (void) +{ + //Dan: Sprite routines not yet converted to fixed point +/* + int i, v, itop, ibottom, lmaxindex; + emitpoint_t *pvert, *pnext; + sspan_t *pspan; + float du, dv, vtop, vbottom, slope; + fixed16_t u, u_step; + + pspan = sprite_spans; + i = minindex; + if (i == 0) + i = r_spritedesc.nump; + + lmaxindex = maxindex; + if (lmaxindex == 0) + lmaxindex = r_spritedesc.nump; + + vtop = ceil (r_spritedesc.pverts[i].v); + + do + { + pvert = &r_spritedesc.pverts[i]; + pnext = pvert - 1; + + vbottom = ceil (pnext->v); + + if (vtop < vbottom) + { + du = pnext->u - pvert->u; + dv = pnext->v - pvert->v; + slope = du / dv; + u_step = (int)(slope * 0x10000); + // adjust u to ceil the integer portion + u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) + + (0x10000 - 1); + itop = (int)vtop; + ibottom = (int)vbottom; + + for (v=itop ; vu = u >> 16; + pspan->v = v; + u += u_step; + pspan++; + } + } + + vtop = vbottom; + + i--; + if (i == 0) + i = r_spritedesc.nump; + + } while (i != lmaxindex); +*/ +} +#endif + +/* +===================== +D_SpriteScanRightEdge +===================== +*/ +void D_SpriteScanRightEdge (void) +{ + int i, v, itop, ibottom; + emitpoint_t *pvert, *pnext; + sspan_t *pspan; + float du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext; + fixed16_t u, u_step; + + pspan = sprite_spans; + i = minindex; + + vvert = r_spritedesc.pverts[i].v; + if (vvert < r_refdef.fvrecty_adj) + vvert = r_refdef.fvrecty_adj; + if (vvert > r_refdef.fvrectbottom_adj) + vvert = r_refdef.fvrectbottom_adj; + + vtop = (float)ceil (vvert); + + do + { + pvert = &r_spritedesc.pverts[i]; + pnext = pvert + 1; + + vnext = pnext->v; + if (vnext < r_refdef.fvrecty_adj) + vnext = r_refdef.fvrecty_adj; + if (vnext > r_refdef.fvrectbottom_adj) + vnext = r_refdef.fvrectbottom_adj; + + vbottom = (float)ceil (vnext); + + if (vtop < vbottom) + { + uvert = pvert->u; + if (uvert < r_refdef.fvrectx_adj) + uvert = r_refdef.fvrectx_adj; + if (uvert > r_refdef.fvrectright_adj) + uvert = r_refdef.fvrectright_adj; + + unext = pnext->u; + if (unext < r_refdef.fvrectx_adj) + unext = r_refdef.fvrectx_adj; + if (unext > r_refdef.fvrectright_adj) + unext = r_refdef.fvrectright_adj; + + du = unext - uvert; + dv = vnext - vvert; + slope = du / dv; + u_step = (int)(slope * 0x10000); + // adjust u to ceil the integer portion + u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) + + (0x10000 - 1); + itop = (int)vtop; + ibottom = (int)vbottom; + + for (v=itop ; vcount = (u >> 16) - pspan->u; + u += u_step; + pspan++; + } + } + + vtop = vbottom; + vvert = vnext; + + i++; + if (i == r_spritedesc.nump) + i = 0; + + } while (i != maxindex); + + pspan->count = DS_SPAN_LIST_END; // mark the end of the span list +} + +#ifdef USEFPM +void D_SpriteScanRightEdgeFPM (void) +{ + //Dan: Sprite routines not yet converted to fixed point +/* + int i, v, itop, ibottom; + emitpoint_t *pvert, *pnext; + sspan_t *pspan; + float du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext; + fixed16_t u, u_step; + + pspan = sprite_spans; + i = minindex; + + vvert = r_spritedesc.pverts[i].v; + if (vvert < r_refdef.fvrecty_adj) + vvert = r_refdef.fvrecty_adj; + if (vvert > r_refdef.fvrectbottom_adj) + vvert = r_refdef.fvrectbottom_adj; + + vtop = ceil (vvert); + + do + { + pvert = &r_spritedesc.pverts[i]; + pnext = pvert + 1; + + vnext = pnext->v; + if (vnext < r_refdef.fvrecty_adj) + vnext = r_refdef.fvrecty_adj; + if (vnext > r_refdef.fvrectbottom_adj) + vnext = r_refdef.fvrectbottom_adj; + + vbottom = ceil (vnext); + + if (vtop < vbottom) + { + uvert = pvert->u; + if (uvert < r_refdef.fvrectx_adj) + uvert = r_refdef.fvrectx_adj; + if (uvert > r_refdef.fvrectright_adj) + uvert = r_refdef.fvrectright_adj; + + unext = pnext->u; + if (unext < r_refdef.fvrectx_adj) + unext = r_refdef.fvrectx_adj; + if (unext > r_refdef.fvrectright_adj) + unext = r_refdef.fvrectright_adj; + + du = unext - uvert; + dv = vnext - vvert; + slope = du / dv; + u_step = (int)(slope * 0x10000); + // adjust u to ceil the integer portion + u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) + + (0x10000 - 1); + itop = (int)vtop; + ibottom = (int)vbottom; + + for (v=itop ; vcount = (u >> 16) - pspan->u; + u += u_step; + pspan++; + } + } + + vtop = vbottom; + vvert = vnext; + + i++; + if (i == r_spritedesc.nump) + i = 0; + + } while (i != maxindex); + + pspan->count = DS_SPAN_LIST_END; // mark the end of the span list +*/ +} +#endif + +/* +===================== +D_SpriteCalculateGradients +===================== +*/ +void D_SpriteCalculateGradients (void) +{ + vec3_t p_normal, p_saxis, p_taxis, p_temp1; + float distinv; + + TransformVector (r_spritedesc.vpn, p_normal); + TransformVector (r_spritedesc.vright, p_saxis); + TransformVector (r_spritedesc.vup, p_taxis); + VectorInverse (p_taxis); + + distinv = (float)(1.0 / (-DotProduct (modelorg, r_spritedesc.vpn))); + + d_sdivzstepu = p_saxis[0] * xscaleinv; + d_tdivzstepu = p_taxis[0] * xscaleinv; + + d_sdivzstepv = -p_saxis[1] * yscaleinv; + d_tdivzstepv = -p_taxis[1] * yscaleinv; + + d_zistepu = p_normal[0] * xscaleinv * distinv; + d_zistepv = -p_normal[1] * yscaleinv * distinv; + + d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu - + ycenter * d_sdivzstepv; + d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu - + ycenter * d_tdivzstepv; + d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu - + ycenter * d_zistepv; + + TransformVector (modelorg, p_temp1); + + sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) - + (-(cachewidth >> 1) << 16); + tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) - + (-(sprite_height >> 1) << 16); + +// -1 (-epsilon) so we never wander off the edge of the texture + bbextents = (cachewidth << 16) - 1; + bbextentt = (sprite_height << 16) - 1; +} + +#ifdef USEFPM +void D_SpriteCalculateGradientsFPM (void) +{ + //Dan: Sprite routines not yet converted to fixed point +/* + vec3_t p_normal, p_saxis, p_taxis, p_temp1; + float distinv; + + TransformVector (r_spritedesc.vpn, p_normal); + TransformVector (r_spritedesc.vright, p_saxis); + TransformVector (r_spritedesc.vup, p_taxis); + VectorInverse (p_taxis); + + distinv = 1.0 / (-DotProduct (modelorg, r_spritedesc.vpn)); + + d_sdivzstepu = p_saxis[0] * xscaleinv; + d_tdivzstepu = p_taxis[0] * xscaleinv; + + d_sdivzstepv = -p_saxis[1] * yscaleinv; + d_tdivzstepv = -p_taxis[1] * yscaleinv; + + d_zistepu = p_normal[0] * xscaleinv * distinv; + d_zistepv = -p_normal[1] * yscaleinv * distinv; + + d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu - + ycenter * d_sdivzstepv; + d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu - + ycenter * d_tdivzstepv; + d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu - + ycenter * d_zistepv; + + TransformVector (modelorg, p_temp1); + + sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) - + (-(cachewidth >> 1) << 16); + tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) - + (-(sprite_height >> 1) << 16); + +// -1 (-epsilon) so we never wander off the edge of the texture + bbextents = (cachewidth << 16) - 1; + bbextentt = (sprite_height << 16) - 1; +*/ +} +#endif + +/* +===================== +D_DrawSprite +===================== +*/ +void D_DrawSprite (void) +{ + int i, nump; + float ymin, ymax; + emitpoint_t *pverts; + sspan_t spans[MAXHEIGHT+1]; + + sprite_spans = spans; + +// find the top and bottom vertices, and make sure there's at least one scan to +// draw + ymin = (float)999999.9; + ymax = (float)-999999.9; + pverts = r_spritedesc.pverts; + + for (i=0 ; iv < ymin) + { + ymin = pverts->v; + minindex = i; + } + + if (pverts->v > ymax) + { + ymax = pverts->v; + maxindex = i; + } + + pverts++; + } + + ymin = (float)ceil (ymin); + ymax = (float)ceil (ymax); + + if (ymin >= ymax) + return; // doesn't cross any scans at all + + cachewidth = r_spritedesc.pspriteframe->width; + sprite_height = r_spritedesc.pspriteframe->height; + cacheblock = (byte *)&r_spritedesc.pspriteframe->pixels[0]; + +// copy the first vertex to the last vertex, so we don't have to deal with +// wrapping + nump = r_spritedesc.nump; + pverts = r_spritedesc.pverts; + pverts[nump] = pverts[0]; + + D_SpriteCalculateGradients (); + D_SpriteScanLeftEdge (); + D_SpriteScanRightEdge (); + D_SpriteDrawSpans (sprite_spans); +} + +#ifdef USEFPM +void D_DrawSpriteFPM (void) +{ + int i, nump; + fixedpoint_t ymin, ymax; + emitpoint_FPM_t *pverts; + sspan_t spans[MAXHEIGHT+1]; + + sprite_spans = spans; + +// find the top and bottom vertices, and make sure there's at least one scan to +// draw + ymin = FPM_FROMFLOAT(999999.9); + ymax = FPM_FROMFLOAT(-999999.9); + pverts = r_spritedescFPM.pverts; + + for (i=0 ; iv < ymin) + { + ymin = pverts->v; + minindex = i; + } + + if (pverts->v > ymax) + { + ymax = pverts->v; + maxindex = i; + } + + pverts++; + } + + ymin = FPM_CEIL (ymin); + ymax = FPM_CEIL (ymax); + + if (ymin >= ymax) + return; // doesn't cross any scans at all + + cachewidth = r_spritedescFPM.pspriteframe->width; + sprite_height = r_spritedescFPM.pspriteframe->height; + cacheblock = (byte *)&r_spritedescFPM.pspriteframe->pixels[0]; + +// copy the first vertex to the last vertex, so we don't have to deal with +// wrapping + nump = r_spritedescFPM.nump; + pverts = r_spritedescFPM.pverts; + pverts[nump] = pverts[0]; + + D_SpriteCalculateGradientsFPM (); + D_SpriteScanLeftEdgeFPM (); + D_SpriteScanRightEdgeFPM (); + D_SpriteDrawSpansFPM (sprite_spans); +} +#endif \ No newline at end of file diff --git a/project/jni/application/quake/source/d_surf.c b/project/jni/application/quake/source/d_surf.c new file mode 100644 index 000000000..ab1ce03b2 --- /dev/null +++ b/project/jni/application/quake/source/d_surf.c @@ -0,0 +1,571 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_surf.c: rasterization driver surface heap manager + +#include "quakedef.h" +#include "d_local.h" +#include "r_local.h" + +float surfscale; +qboolean r_cache_thrash; // set if surface cache is thrashing + +int sc_size; +surfcache_t *sc_rover, *sc_base; + +#ifdef USEFPM +fixedpoint_t surfscaleFPM; +surfcache_FPM_t *sc_roverFPM, *sc_baseFPM; +#endif + +#define GUARDSIZE 4 + + +int D_SurfaceCacheForRes (int width, int height) +{ + int size, pix; + + if (COM_CheckParm ("-surfcachesize")) + { + size = Q_atoi(com_argv[COM_CheckParm("-surfcachesize")+1]) * 1024; + return size; + } + + size = SURFCACHE_SIZE_AT_320X200; + + pix = width*height; + if (pix > 64000) + size += (pix-64000)*3; + + + return size; +} + +void D_CheckCacheGuard (void) +{ + byte *s; + int i; + + s = (byte *)sc_base + sc_size; + for (i=0 ; inext = NULL; + sc_base->owner = NULL; + sc_base->size = sc_size; + + D_ClearCacheGuard (); +} + +#ifdef USEFPM +void D_InitCachesFPM (void *buffer, int size) +{ + + if (!msg_suppress_1) + Con_Printf ("%ik surface cache\n", size/1024); + + sc_size = size - GUARDSIZE; + sc_baseFPM = (surfcache_FPM_t *)buffer; + sc_roverFPM = sc_baseFPM; + + sc_baseFPM->next = NULL; + sc_baseFPM->owner = NULL; + sc_baseFPM->size = sc_size; + + D_ClearCacheGuardFPM (); +} +#endif + +/* +================== +D_FlushCaches +================== +*/ +void D_FlushCaches (void) +{ + surfcache_t *c; + + if (!sc_base) + return; + + for (c = sc_base ; c ; c = c->next) + { + if (c->owner) + *c->owner = NULL; + } + + sc_rover = sc_base; + sc_base->next = NULL; + sc_base->owner = NULL; + sc_base->size = sc_size; +} + +#ifdef USEFPM +void D_FlushCachesFPM (void) +{ + surfcache_FPM_t *c; + + if (!sc_baseFPM) + return; + + for (c = sc_baseFPM ; c ; c = c->next) + { + if (c->owner) + *c->owner = NULL; + } + + sc_roverFPM = sc_baseFPM; + sc_baseFPM->next = NULL; + sc_baseFPM->owner = NULL; + sc_baseFPM->size = sc_size; +} +#endif + +/* +================= +D_SCAlloc +================= +*/ +surfcache_t *D_SCAlloc (int width, int size) +{ + surfcache_t *new; + qboolean wrapped_this_time; + + if ((width < 0) || (width > 256)) + Sys_Error ("D_SCAlloc: bad cache width %d\n", width); + + if ((size <= 0) || (size > 0x10000)) + Sys_Error ("D_SCAlloc: bad cache size %d\n", size); + + size = (int)&((surfcache_t *)0)->data[size]; + size = (size + 3) & ~3; + if (size > sc_size) + Sys_Error ("D_SCAlloc: %i > cache size",size); + +// if there is not size bytes after the rover, reset to the start + wrapped_this_time = false; + + if ( !sc_rover || (byte *)sc_rover - (byte *)sc_base > sc_size - size) + { + if (sc_rover) + { + wrapped_this_time = true; + } + sc_rover = sc_base; + } + +// colect and free surfcache_t blocks until the rover block is large enough + new = sc_rover; + if (sc_rover->owner) + *sc_rover->owner = NULL; + + while (new->size < size) + { + // free another + sc_rover = sc_rover->next; + if (!sc_rover) + Sys_Error ("D_SCAlloc: hit the end of memory"); + if (sc_rover->owner) + *sc_rover->owner = NULL; + + new->size += sc_rover->size; + new->next = sc_rover->next; + } + +// create a fragment out of any leftovers + if (new->size - size > 256) + { + sc_rover = (surfcache_t *)( (byte *)new + size); + sc_rover->size = new->size - size; + sc_rover->next = new->next; + sc_rover->width = 0; + sc_rover->owner = NULL; + new->next = sc_rover; + new->size = size; + } + else + sc_rover = new->next; + + new->width = width; +// DEBUG + if (width > 0) + new->height = (size - sizeof(*new) + sizeof(new->data)) / width; + + new->owner = NULL; // should be set properly after return + + if (d_roverwrapped) + { + if (wrapped_this_time || (sc_rover >= d_initial_rover)) + r_cache_thrash = true; + } + else if (wrapped_this_time) + { + d_roverwrapped = true; + } + +D_CheckCacheGuard (); // DEBUG + return new; +} + +#ifdef USEFPM +surfcache_FPM_t *D_SCAllocFPM (int width, int size) +{ + surfcache_FPM_t *new; + qboolean wrapped_this_time; + + if ((width < 0) || (width > 256)) + Sys_Error ("D_SCAlloc: bad cache width %d\n", width); + + if ((size <= 0) || (size > 0x10000)) + Sys_Error ("D_SCAlloc: bad cache size %d\n", size); + + size = (int)&((surfcache_FPM_t *)0)->data[size]; + size = (size + 3) & ~3; + if (size > sc_size) + Sys_Error ("D_SCAlloc: %i > cache size",size); + +// if there is not size bytes after the rover, reset to the start + wrapped_this_time = false; + + if ( !sc_roverFPM || (byte *)sc_roverFPM - (byte *)sc_baseFPM > sc_size - size) + { + if (sc_roverFPM) + { + wrapped_this_time = true; + } + sc_roverFPM = sc_baseFPM; + } + +// colect and free surfcache_t blocks until the rover block is large enough + new = sc_roverFPM; + if (sc_roverFPM->owner) + *sc_roverFPM->owner = NULL; + + while (new->size < size) + { + // free another + sc_roverFPM = sc_roverFPM->next; + if (!sc_roverFPM) + Sys_Error ("D_SCAlloc: hit the end of memory"); + if (sc_roverFPM->owner) + *sc_roverFPM->owner = NULL; + + new->size += sc_roverFPM->size; + new->next = sc_roverFPM->next; + } + +// create a fragment out of any leftovers + if (new->size - size > 256) + { + sc_roverFPM = (surfcache_FPM_t *)( (byte *)new + size); + sc_roverFPM->size = new->size - size; + sc_roverFPM->next = new->next; + sc_roverFPM->width = 0; + sc_roverFPM->owner = NULL; + new->next = sc_roverFPM; + new->size = size; + } + else + sc_roverFPM = new->next; + + new->width = width; +// DEBUG + if (width > 0) + new->height = (size - sizeof(*new) + sizeof(new->data)) / width; + + new->owner = NULL; // should be set properly after return + + if (d_roverwrapped) + { + if (wrapped_this_time || (sc_roverFPM >= d_initial_roverFPM)) + r_cache_thrash = true; + } + else if (wrapped_this_time) + { + d_roverwrapped = true; + } + + D_CheckCacheGuardFPM (); // DEBUG + return new; +} +#endif + +/* +================= +D_SCDump +================= +*/ +void D_SCDump (void) +{ + surfcache_t *test; + + for (test = sc_base ; test ; test = test->next) + { + if (test == sc_rover) + Sys_Printf ("ROVER:\n"); + printf ("%p : %i bytes %i width\n",test, test->size, test->width); + } +} + +#ifdef USEFPM +void D_SCDumpFPM (void) +{ + surfcache_FPM_t *test; + + for (test = sc_baseFPM ; test ; test = test->next) + { + if (test == sc_roverFPM) + Sys_Printf ("ROVER:\n"); + printf ("%p : %i bytes %i width\n",test, test->size, test->width); + } +} +#endif + +//============================================================================= + +// if the num is not a power of 2, assume it will not repeat + +int MaskForNum (int num) +{ + if (num==128) + return 127; + if (num==64) + return 63; + if (num==32) + return 31; + if (num==16) + return 15; + return 255; +} + +int D_log2 (int num) +{ + int c; + + c = 0; + + while (num>>=1) + c++; + return c; +} + +//============================================================================= + +/* +================ +D_CacheSurface +================ +*/ +surfcache_t *D_CacheSurface (msurface_t *surface, int miplevel) +{ + surfcache_t *cache; + +// +// if the surface is animating or flashing, flush the cache +// + r_drawsurf.texture = R_TextureAnimation (surface->texinfo->texture); + r_drawsurf.lightadj[0] = d_lightstylevalue[surface->styles[0]]; + r_drawsurf.lightadj[1] = d_lightstylevalue[surface->styles[1]]; + r_drawsurf.lightadj[2] = d_lightstylevalue[surface->styles[2]]; + r_drawsurf.lightadj[3] = d_lightstylevalue[surface->styles[3]]; + +// +// see if the cache holds apropriate data +// + cache = surface->cachespots[miplevel]; + + if (cache && !cache->dlight && surface->dlightframe != r_framecount + && cache->texture == r_drawsurf.texture + && cache->lightadj[0] == r_drawsurf.lightadj[0] + && cache->lightadj[1] == r_drawsurf.lightadj[1] + && cache->lightadj[2] == r_drawsurf.lightadj[2] + && cache->lightadj[3] == r_drawsurf.lightadj[3] ) + return cache; + +// +// determine shape of surface +// + surfscale = (float) 1.0 / (1<extents[0] >> miplevel; + r_drawsurf.rowbytes = r_drawsurf.surfwidth; + r_drawsurf.surfheight = surface->extents[1] >> miplevel; + +// +// allocate memory if needed +// + if (!cache) // if a texture just animated, don't reallocate it + { + cache = D_SCAlloc (r_drawsurf.surfwidth, + r_drawsurf.surfwidth * r_drawsurf.surfheight); + surface->cachespots[miplevel] = cache; + cache->owner = &surface->cachespots[miplevel]; + cache->mipscale = surfscale; + } + + if (surface->dlightframe == r_framecount) + cache->dlight = 1; + else + cache->dlight = 0; + + r_drawsurf.surfdat = (pixel_t *)cache->data; + + cache->texture = r_drawsurf.texture; + cache->lightadj[0] = r_drawsurf.lightadj[0]; + cache->lightadj[1] = r_drawsurf.lightadj[1]; + cache->lightadj[2] = r_drawsurf.lightadj[2]; + cache->lightadj[3] = r_drawsurf.lightadj[3]; + +// +// draw and light the surface texture +// + r_drawsurf.surf = surface; + + c_surf++; + R_DrawSurface (); + + return surface->cachespots[miplevel]; +} + +#ifdef USEFPM +surfcache_FPM_t *D_CacheSurfaceFPM (msurface_FPM_t *surface, int miplevel) +{ + surfcache_FPM_t *cache; + +// +// if the surface is animating or flashing, flush the cache +// + r_drawsurfFPM.texture = R_TextureAnimationFPM (surface->texinfo->texture); + r_drawsurfFPM.lightadj[0] = d_lightstylevalue[surface->styles[0]]; + r_drawsurfFPM.lightadj[1] = d_lightstylevalue[surface->styles[1]]; + r_drawsurfFPM.lightadj[2] = d_lightstylevalue[surface->styles[2]]; + r_drawsurfFPM.lightadj[3] = d_lightstylevalue[surface->styles[3]]; + +// +// see if the cache holds apropriate data +// + cache = surface->cachespots[miplevel]; + + if (cache && !cache->dlight && surface->dlightframe != r_framecount + && cache->texture == r_drawsurfFPM.texture + && cache->lightadj[0] == r_drawsurfFPM.lightadj[0] + && cache->lightadj[1] == r_drawsurfFPM.lightadj[1] + && cache->lightadj[2] == r_drawsurfFPM.lightadj[2] + && cache->lightadj[3] == r_drawsurfFPM.lightadj[3] ) + return cache; + +// +// determine shape of surface +// + surfscaleFPM = FPM_INV(FPM_FROMLONG(1<extents[0] >> miplevel; + r_drawsurfFPM.rowbytes = r_drawsurfFPM.surfwidth; + r_drawsurfFPM.surfheight = surface->extents[1] >> miplevel; + +// +// allocate memory if needed +// + if (!cache) // if a texture just animated, don't reallocate it + { + cache = (surfcache_FPM_t *)D_SCAllocFPM (r_drawsurfFPM.surfwidth, + r_drawsurfFPM.surfwidth * r_drawsurfFPM.surfheight); + surface->cachespots[miplevel] = cache; + cache->owner = &surface->cachespots[miplevel]; + cache->mipscale = surfscaleFPM; + } + + if (surface->dlightframe == r_framecount) + cache->dlight = 1; + else + cache->dlight = 0; + + r_drawsurfFPM.surfdat = (pixel_t *)cache->data; + + cache->texture = r_drawsurfFPM.texture; + cache->lightadj[0] = r_drawsurfFPM.lightadj[0]; + cache->lightadj[1] = r_drawsurfFPM.lightadj[1]; + cache->lightadj[2] = r_drawsurfFPM.lightadj[2]; + cache->lightadj[3] = r_drawsurfFPM.lightadj[3]; + +// +// draw and light the surface texture +// + r_drawsurfFPM.surf = surface; + + c_surf++; + R_DrawSurfaceFPM (); + + return surface->cachespots[miplevel]; +} +#endif + diff --git a/project/jni/application/quake/source/d_vars.c b/project/jni/application/quake/source/d_vars.c new file mode 100644 index 000000000..e24004963 --- /dev/null +++ b/project/jni/application/quake/source/d_vars.c @@ -0,0 +1,70 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_vars.c: global refresh variables + +#if !id386 + +#include "quakedef.h" + +// all global and static refresh variables are collected in a contiguous block +// to avoid cache conflicts. + +//------------------------------------------------------- +// global refresh variables +//------------------------------------------------------- + +// FIXME: make into one big structure, like cl or sv +// FIXME: do separately for refresh engine and driver + +float d_sdivzstepu, d_tdivzstepu, d_zistepu; +float d_sdivzstepv, d_tdivzstepv, d_zistepv; +float d_sdivzorigin, d_tdivzorigin, d_ziorigin; +#ifdef USE_PQ_OPT3 +int d_sdivzstepu_fxp, d_tdivzstepu_fxp, d_zistepu_fxp; +int d_sdivzstepv_fxp, d_tdivzstepv_fxp, d_zistepv_fxp; +int d_sdivzorigin_fxp, d_tdivzorigin_fxp, d_ziorigin_fxp; +#endif + +int d_ziorigin_fxp, d_zistepv_fxp, d_zistepu_fxp; + +#ifdef USE_PQ_OPT +//JB: Optimization +int sdivzstepu, tdivzstepu, zistepu; +int sdivzstepv, tdivzstepv, zistepv; +int sdivzorigin, tdivzorigin, ziorigin; +#endif + +#ifdef USEFPM +fixedpoint_t d_sdivzstepuFPM, d_tdivzstepuFPM, d_zistepuFPM; +fixedpoint_t d_sdivzstepvFPM, d_tdivzstepvFPM, d_zistepvFPM; +fixedpoint_t d_sdivzoriginFPM, d_tdivzoriginFPM, d_zioriginFPM; +#endif + +fixed16_t sadjust, tadjust, bbextents, bbextentt; + +pixel_t *cacheblock; +int cachewidth; +pixel_t *d_viewbuffer; +short *d_pzbuffer; +unsigned int d_zrowbytes; +unsigned int d_zwidth; + +#endif // !id386 + diff --git a/project/jni/application/quake/source/d_zpoint.c b/project/jni/application/quake/source/d_zpoint.c new file mode 100644 index 000000000..153cc4438 --- /dev/null +++ b/project/jni/application/quake/source/d_zpoint.c @@ -0,0 +1,67 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// d_zpoint.c: software driver module for drawing z-buffered points + +#include "quakedef.h" +#include "d_local.h" + + +/* +===================== +D_DrawZPoint +===================== +*/ +void D_DrawZPoint (void) +{ + byte *pdest; + short *pz; + int izi; + + pz = d_pzbuffer + (d_zwidth * r_zpointdesc.v) + r_zpointdesc.u; + pdest = d_viewbuffer + d_scantable[r_zpointdesc.v] + r_zpointdesc.u; + izi = (int)(r_zpointdesc.zi * 0x8000); + + if (*pz <= izi) + { + *pz = izi; + *pdest = r_zpointdesc.color; + } +} + +#ifdef USEFPM +void D_DrawZPointFPM (void) +{ + byte *pdest; + short *pz; + int izi; + + pz = d_pzbuffer + (d_zwidth * r_zpointdescFPM.v) + r_zpointdescFPM.u; + pdest = d_viewbuffer + d_scantable[r_zpointdescFPM.v] + r_zpointdescFPM.u; + //Dan: Is this right? + izi = FPM_TOLONG(r_zpointdescFPM.zi>>1); +// izi = (int)(r_zpointdescFPM.zi * 0x8000); + + if (*pz <= izi) + { + *pz = izi; + *pdest = r_zpointdescFPM.color; + } +} +#endif \ No newline at end of file diff --git a/project/jni/application/quake/source/draw.c b/project/jni/application/quake/source/draw.c new file mode 100644 index 000000000..622a02212 --- /dev/null +++ b/project/jni/application/quake/source/draw.c @@ -0,0 +1,938 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// draw.c -- this is the only file outside the refresh that touches the +// vid buffer + +#include "quakedef.h" + +typedef struct { + vrect_t rect; + int width; + int height; + byte *ptexbytes; + int rowbytes; +} rectdesc_t; + +static rectdesc_t r_rectdesc; + +byte *draw_chars; // 8*8 graphic characters +qpic_t *draw_disc; +qpic_t *draw_backtile; + +//============================================================================= +/* Support Routines */ + +typedef struct cachepic_s +{ + char name[MAX_QPATH]; + cache_user_t cache; +} cachepic_t; + +#define MAX_CACHED_PICS 128 +cachepic_t menu_cachepics[MAX_CACHED_PICS]; +int menu_numcachepics; + + +qpic_t *Draw_PicFromWad (char *name) +{ + return W_GetLumpName (name); +} + +/* +================ +Draw_CachePic +================ +*/ +qpic_t *Draw_CachePic (char *path) +{ + cachepic_t *pic; + int i; + qpic_t *dat; + + for (pic=menu_cachepics, i=0 ; iname)) + break; + + if (i == menu_numcachepics) + { + if (menu_numcachepics == MAX_CACHED_PICS) + Sys_Error ("menu_numcachepics == MAX_CACHED_PICS"); + menu_numcachepics++; + strcpy (pic->name, path); + } + + dat = Cache_Check (&pic->cache); + + if (dat) + return dat; + +// +// load the pic from disk +// + COM_LoadCacheFile (path, &pic->cache); + + dat = (qpic_t *)pic->cache.data; + if (!dat) + { + Sys_Error ("Draw_CachePic: failed to load %s", path); + } + + SwapPic (dat); + + return dat; +} + + + +/* +=============== +Draw_Init +=============== +*/ +void Draw_Init (void) +{ +// int i; + + draw_chars = W_GetLumpName ("conchars"); + draw_disc = W_GetLumpName ("disc"); + draw_backtile = W_GetLumpName ("backtile"); + + r_rectdesc.width = draw_backtile->width; + r_rectdesc.height = draw_backtile->height; + r_rectdesc.ptexbytes = draw_backtile->data; + r_rectdesc.rowbytes = draw_backtile->width; +} + + + +/* +================ +Draw_Character + +Draws one 8*8 graphics character with 0 being transparent. +It can be clipped to the top of the screen to allow the console to be +smoothly scrolled off. +================ +*/ +void Draw_Character (int x, int y, int num) +{ + byte *dest; + byte *source; + unsigned short *pusdest; + int drawline; + int row, col; + + num &= 255; + + if (y <= -8) + return; // totally off screen + +#ifdef PARANOID + if (y > vid.height - 8 || x < 0 || x > vid.width - 8) + Sys_Error ("Con_DrawCharacter: (%i, %i)", x, y); + if (num < 0 || num > 255) + Sys_Error ("Con_DrawCharacter: char %i", num); +#endif + + row = num>>4; + col = num&15; + source = draw_chars + (row<<10) + (col<<3); + + if (y < 0) + { // clipped + drawline = 8 + y; + source -= 128*y; + y = 0; + } + else + drawline = 8; + + + if (r_pixbytes == 1) + { + dest = vid.conbuffer + y*vid.conrowbytes + x; + + while (drawline--) + { + if (source[0]) + dest[0] = source[0]; + if (source[1]) + dest[1] = source[1]; + if (source[2]) + dest[2] = source[2]; + if (source[3]) + dest[3] = source[3]; + if (source[4]) + dest[4] = source[4]; + if (source[5]) + dest[5] = source[5]; + if (source[6]) + dest[6] = source[6]; + if (source[7]) + dest[7] = source[7]; + source += 128; + dest += vid.conrowbytes; + } + } + else + { + // FIXME: pre-expand to native format? + pusdest = (unsigned short *) + ((byte *)vid.conbuffer + y*vid.conrowbytes + (x<<1)); + + while (drawline--) + { + if (source[0]) + pusdest[0] = d_8to16table[source[0]]; + if (source[1]) + pusdest[1] = d_8to16table[source[1]]; + if (source[2]) + pusdest[2] = d_8to16table[source[2]]; + if (source[3]) + pusdest[3] = d_8to16table[source[3]]; + if (source[4]) + pusdest[4] = d_8to16table[source[4]]; + if (source[5]) + pusdest[5] = d_8to16table[source[5]]; + if (source[6]) + pusdest[6] = d_8to16table[source[6]]; + if (source[7]) + pusdest[7] = d_8to16table[source[7]]; + + source += 128; + pusdest += (vid.conrowbytes >> 1); + } + } +} + +/* +================ +Draw_String +================ +*/ +void Draw_String (int x, int y, char *str) +{ + while (*str) + { + Draw_Character (x, y, *str); + str++; + x += 8; + } +} + +/* +================ +Draw_DebugChar + +Draws a single character directly to the upper right corner of the screen. +This is for debugging lockups by drawing different chars in different parts +of the code. +================ +*/ +void Draw_DebugChar (char num) +{ + byte *dest; + byte *source; + int drawline; + extern byte *draw_chars; + int row, col; + + if (!vid.direct) + return; // don't have direct FB access, so no debugchars... + + drawline = 8; + + row = num>>4; + col = num&15; + source = draw_chars + (row<<10) + (col<<3); + + dest = vid.direct + 312; + + while (drawline--) + { + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; + dest[4] = source[4]; + dest[5] = source[5]; + dest[6] = source[6]; + dest[7] = source[7]; + source += 128; + dest += 320; + } +} + +/* +============= +Draw_Pic +============= +*/ +void Draw_Pic (int x, int y, qpic_t *pic) +{ +// byte *dest, *source; +// unsigned short *pusdest; +// int v, u; + + Draw_TransPic(x, y, pic); + /* + if ((x < 0) || + (x + pic->width > vid.width) || + (y < 0) || + (y + pic->height > vid.height)) + { + Sys_Error ("Draw_Pic: bad coordinates"); + } + + source = pic->data; + + if (r_pixbytes == 1) + { + dest = vid.buffer + y * vid.rowbytes + x; + + for (v=0 ; vheight ; v++) + { + Q_memcpy (dest, source, pic->width); + dest += vid.rowbytes; + source += pic->width; + } + } + else + { + // FIXME: pretranslate at load time? + pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x; + + for (v=0 ; vheight ; v++) + { + for (u=0 ; uwidth ; u++) + { + pusdest[u] = d_8to16table[source[u]]; + } + + pusdest += vid.rowbytes >> 1; + source += pic->width; + } + } + */ +} + + +/* +============= +Draw_TransPic +============= +*/ +void Draw_TransPic (int x, int y, qpic_t *pic) +{ + byte *dest, *source, tbyte; + unsigned short *pusdest; + int v, u; + int w, h; + + if (x < 0 || y < 0) + { + Sys_Error ("Draw_TransPic: bad coordinates"); + } + + if ((unsigned)(x + pic->width) > vid.width) w=vid.width-x; + else w=pic->width; + + if ((unsigned)(y + pic->height) > vid.height) h=vid.height-y; + else h=pic->height; + +/* + if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 || + (unsigned)(y + pic->height) > vid.height) + { + Sys_Error ("Draw_TransPic: bad coordinates"); + } +*/ + source = pic->data; + + if (r_pixbytes == 1) + { + dest = vid.buffer + y * vid.rowbytes + x; + + if (pic->width & 7) + { // general + for (v=0 ; vheight*/ ; v++) + { + for (u=0 ; uwidth*/ ; u++) + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + dest[u] = tbyte; + + dest += vid.rowbytes; + source += pic->width; + } + } + else + { // unwound + for (v=0 ; vheight*/ ; v++) + { + for (u=0 ; uwidth*/ ; u+=8) + { + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + dest[u] = tbyte; + if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR) + dest[u+1] = tbyte; + if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR) + dest[u+2] = tbyte; + if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR) + dest[u+3] = tbyte; + if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR) + dest[u+4] = tbyte; + if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR) + dest[u+5] = tbyte; + if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR) + dest[u+6] = tbyte; + if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR) + dest[u+7] = tbyte; + } + dest += vid.rowbytes; + source += pic->width; + } + } + } + else + { + // FIXME: pretranslate at load time? + pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x; + + for (v=0 ; vheight*/ ; v++) + { + for (u=0 ; uwidth*/ ; u++) + { + tbyte = source[u]; + + if (tbyte != TRANSPARENT_COLOR) + { + pusdest[u] = d_8to16table[tbyte]; + } + } + + pusdest += vid.rowbytes >> 1; + source += pic->width; + } + } +} + + +/* +============= +Draw_TransPicTranslate +============= +*/ +void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation) +{ + byte *dest, *source, tbyte; + unsigned short *pusdest; + int v, u; + int w, h; +/* + if (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 || + (unsigned)(y + pic->height) > vid.height) + { + Sys_Error ("Draw_TransPic: bad coordinates"); + } +*/ + if (x < 0 || y < 0) + { + Sys_Error ("Draw_TransPicTranslate: bad coordinates"); + } + + if ((unsigned)(x + pic->width) > vid.width) w=vid.width-x; + else w=pic->width; + + if ((unsigned)(y + pic->height) > vid.height) w=vid.height-y; + else h=pic->height; + + source = pic->data; + + if (r_pixbytes == 1) + { + dest = vid.buffer + y * vid.rowbytes + x; + + if (w /*pic->width*/ & 7) + { // general + for (v=0 ; vheight*/ ; v++) + { + for (u=0 ; uwidth*/ ; u++) + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + dest[u] = translation[tbyte]; + + dest += vid.rowbytes; + source += pic->width; + } + } + else + { // unwound + for (v=0 ; vheight*/ ; v++) + { + for (u=0 ; uwidth*/ ; u+=8) + { + if ( (tbyte=source[u]) != TRANSPARENT_COLOR) + dest[u] = translation[tbyte]; + if ( (tbyte=source[u+1]) != TRANSPARENT_COLOR) + dest[u+1] = translation[tbyte]; + if ( (tbyte=source[u+2]) != TRANSPARENT_COLOR) + dest[u+2] = translation[tbyte]; + if ( (tbyte=source[u+3]) != TRANSPARENT_COLOR) + dest[u+3] = translation[tbyte]; + if ( (tbyte=source[u+4]) != TRANSPARENT_COLOR) + dest[u+4] = translation[tbyte]; + if ( (tbyte=source[u+5]) != TRANSPARENT_COLOR) + dest[u+5] = translation[tbyte]; + if ( (tbyte=source[u+6]) != TRANSPARENT_COLOR) + dest[u+6] = translation[tbyte]; + if ( (tbyte=source[u+7]) != TRANSPARENT_COLOR) + dest[u+7] = translation[tbyte]; + } + dest += vid.rowbytes; + source += pic->width; + } + } + } + else + { + // FIXME: pretranslate at load time? + pusdest = (unsigned short *)vid.buffer + y * (vid.rowbytes >> 1) + x; + + for (v=0 ; vheight*/ ; v++) + { + for (u=0 ; uwidth*/ ; u++) + { + tbyte = source[u]; + + if (tbyte != TRANSPARENT_COLOR) + { + pusdest[u] = d_8to16table[tbyte]; + } + } + + pusdest += vid.rowbytes >> 1; + source += pic->width; + } + } +} + + +void Draw_CharToConback (int num, byte *dest) +{ + int row, col; + byte *source; + int drawline; + int x; + + row = num>>4; + col = num&15; + source = draw_chars + (row<<10) + (col<<3); + + drawline = 8; + + while (drawline--) + { + for (x=0 ; x<8 ; x++) + if (source[x]) + dest[x] = 0x60 + source[x]; + source += 128; + dest += 320; + } + +} + +/* +================ +Draw_ConsoleBackground + +================ +*/ +void Draw_ConsoleBackground (int lines) +{ + + int x, y, v; + byte *src, *dest; + unsigned short *pusdest; + int f, fstep; + qpic_t *conback; + char ver[256]; + + conback = Draw_CachePic ("gfx/conback.lmp"); + +// hack the version number directly into the pic + +// sprintf (ver, "(Pocket Quake) %4.2f", (float)VERSION); + sprintf (ver, "Quake(SDL) %4.2f R2-Tec", (float)GP2X_VERSION); + dest = conback->data + 320*186 + 320 - 11 - 8*strlen(ver); +/* +#ifdef _WIN32 + sprintf (ver, "(WinQuake) %4.2f", (float)VERSION); + dest = conback->data + 320*186 + 320 - 11 - 8*strlen(ver); +#elif defined(X11) + sprintf (ver, "(X11 Quake %2.2f) %4.2f", (float)X11_VERSION, (float)VERSION); + dest = conback->data + 320*186 + 320 - 11 - 8*strlen(ver); +#elif defined(__linux__) + sprintf (ver, "(Linux Quake %2.2f) %4.2f", (float)LINUX_VERSION, (float)VERSION); + dest = conback->data + 320*186 + 320 - 11 - 8*strlen(ver); +#else + dest = conback->data + 320 - 43 + 320*186; + sprintf (ver, "%4.2f", VERSION); +#endif +*/ + for (x=0 ; x<(int)strlen(ver) ; x++) + Draw_CharToConback (ver[x], dest+(x<<3)); + +// draw the pic + + if (r_pixbytes == 1) + { + dest = vid.conbuffer; + + for (y=0 ; ydata + v*320; + if (vid.conwidth == 320){ + Q_memcpy (dest, src, vid.conwidth); + } + else + { + f = 0; + fstep = 320*0x10000/vid.conwidth; + for (x=0 ; x<(int)vid.conwidth ; x+=4) + { + dest[x] = src[f>>16]; + f += fstep; + dest[x+1] = src[f>>16]; + f += fstep; + dest[x+2] = src[f>>16]; + f += fstep; + dest[x+3] = src[f>>16]; + f += fstep; + } + } + } + } + else + { + GpError("r_pixbytes = 1", 0); + pusdest = (unsigned short *)vid.conbuffer; + + for (y=0 ; y> 1)) + { + // FIXME: pre-expand to native format? + // FIXME: does the endian switching go away in production? + v = (vid.conheight - lines + y)*200/vid.conheight; + src = conback->data + v*320; + f = 0; + fstep = 320*0x10000/vid.conwidth; + for (x=0 ; x<(int)vid.conwidth ; x+=4) + { + pusdest[x] = d_8to16table[src[f>>16]]; + f += fstep; + pusdest[x+1] = d_8to16table[src[f>>16]]; + f += fstep; + pusdest[x+2] = d_8to16table[src[f>>16]]; + f += fstep; + pusdest[x+3] = d_8to16table[src[f>>16]]; + f += fstep; + } + } + } +} + + +/* +============== +R_DrawRect8 +============== +*/ +void R_DrawRect8 (vrect_t *prect, int rowbytes, byte *psrc, + int transparent) +{ + byte t; + int i, j, srcdelta, destdelta; + byte *pdest; + + pdest = vid.buffer + (prect->y * vid.rowbytes) + prect->x; + + srcdelta = rowbytes - prect->width; + destdelta = vid.rowbytes - prect->width; + + if (transparent) + { + for (i=0 ; iheight ; i++) + { + for (j=0 ; jwidth ; j++) + { + t = *psrc; + if (t != TRANSPARENT_COLOR) + { + *pdest = t; + } + + psrc++; + pdest++; + } + + psrc += srcdelta; + pdest += destdelta; + } + } + else + { + for (i=0 ; iheight ; i++) + { + Q_memcpy (pdest, psrc, prect->width); + psrc += rowbytes; + pdest += vid.rowbytes; + } + } +} + + +/* +============== +R_DrawRect16 +============== +*/ +void R_DrawRect16 (vrect_t *prect, int rowbytes, byte *psrc, + int transparent) +{ + byte t; + int i, j, srcdelta, destdelta; + unsigned short *pdest; + +// FIXME: would it be better to pre-expand native-format versions? + + pdest = (unsigned short *)vid.buffer + + (prect->y * (vid.rowbytes >> 1)) + prect->x; + + srcdelta = rowbytes - prect->width; + destdelta = (vid.rowbytes >> 1) - prect->width; + + if (transparent) + { + for (i=0 ; iheight ; i++) + { + for (j=0 ; jwidth ; j++) + { + t = *psrc; + if (t != TRANSPARENT_COLOR) + { + *pdest = d_8to16table[t]; + } + + psrc++; + pdest++; + } + + psrc += srcdelta; + pdest += destdelta; + } + } + else + { + for (i=0 ; iheight ; i++) + { + for (j=0 ; jwidth ; j++) + { + *pdest = d_8to16table[*psrc]; + psrc++; + pdest++; + } + + psrc += srcdelta; + pdest += destdelta; + } + } +} + + +/* +============= +Draw_TileClear + +This repeats a 64*64 tile graphic to fill the screen around a sized down +refresh window. +============= +*/ +void Draw_TileClear (int x, int y, int w, int h) +{ + int width, height, tileoffsetx, tileoffsety; + byte *psrc; + vrect_t vr; + + r_rectdesc.rect.x = x; + r_rectdesc.rect.y = y; + r_rectdesc.rect.width = w; + r_rectdesc.rect.height = h; + + vr.y = r_rectdesc.rect.y; + height = r_rectdesc.rect.height; + + tileoffsety = vr.y % r_rectdesc.height; + + while (height > 0) + { + vr.x = r_rectdesc.rect.x; + width = r_rectdesc.rect.width; + + if (tileoffsety != 0) + vr.height = r_rectdesc.height - tileoffsety; + else + vr.height = r_rectdesc.height; + + if (vr.height > height) + vr.height = height; + + tileoffsetx = vr.x % r_rectdesc.width; + + while (width > 0) + { + if (tileoffsetx != 0) + vr.width = r_rectdesc.width - tileoffsetx; + else + vr.width = r_rectdesc.width; + + if (vr.width > width) + vr.width = width; + + psrc = r_rectdesc.ptexbytes + + (tileoffsety * r_rectdesc.rowbytes) + tileoffsetx; + + if (r_pixbytes == 1) + { + R_DrawRect8 (&vr, r_rectdesc.rowbytes, psrc, 0); + } + else + { + R_DrawRect16 (&vr, r_rectdesc.rowbytes, psrc, 0); + } + + vr.x += vr.width; + width -= vr.width; + tileoffsetx = 0; // only the left tile can be left-clipped + } + + vr.y += vr.height; + height -= vr.height; + tileoffsety = 0; // only the top tile can be top-clipped + } +} + + +/* +============= +Draw_Fill + +Fills a box of pixels with a single color +============= +*/ +void Draw_Fill (int x, int y, int w, int h, int c) +{ + byte *dest; + unsigned short *pusdest; + unsigned uc; + int u, v; + + if (r_pixbytes == 1) + { + dest = vid.buffer + y*vid.rowbytes + x; + for (v=0 ; v> 1) + x; + for (v=0 ; v> 1)) + for (u=0 ; udata, 24, 24); +} + + +/* +================ +Draw_EndDisc + +Erases the disc icon. +Call after completing any disc IO +================ +*/ +void Draw_EndDisc (void) +{ + + D_EndDirectRect (vid.width - 24, 0, 24, 24); +} + diff --git a/project/jni/application/quake/source/draw.h b/project/jni/application/quake/source/draw.h new file mode 100644 index 000000000..e54999c47 --- /dev/null +++ b/project/jni/application/quake/source/draw.h @@ -0,0 +1,40 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// draw.h -- these are the only functions outside the refresh allowed +// to touch the vid buffer + +extern qpic_t *draw_disc; // also used on sbar + +void Draw_Init (void); +void Draw_Character (int x, int y, int num); +void Draw_DebugChar (char num); +void Draw_Pic (int x, int y, qpic_t *pic); +void Draw_TransPic (int x, int y, qpic_t *pic); +void Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation); +void Draw_ConsoleBackground (int lines); +void Draw_BeginDisc (void); +void Draw_EndDisc (void); +void Draw_TileClear (int x, int y, int w, int h); +void Draw_Fill (int x, int y, int w, int h, int c); +void Draw_FadeScreen (void); +void Draw_String (int x, int y, char *str); +qpic_t *Draw_PicFromWad (char *name); +qpic_t *Draw_CachePic (char *path); diff --git a/project/jni/application/quake/source/host.c b/project/jni/application/quake/source/host.c new file mode 100644 index 000000000..8a776e496 --- /dev/null +++ b/project/jni/application/quake/source/host.c @@ -0,0 +1,1137 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// host.c -- coordinates spawning and killing of local servers + +#include "quakedef.h" +#include "r_local.h" + +/* + +A server can allways be started, even if the system started out as a client +to a remote system. + +A client can NOT be started if the system started as a dedicated server. + +Memory is cleared / released when a server or client begins, not when they end. + +*/ + +quakeparms_t host_parms; + +qboolean host_initialized; // true if into command execution + +double host_frametime; +double host_time; +double realtime; // without any filtering or bounding +double oldrealtime; // last frame run +int host_framecount; + +int host_hunklevel; + +int minimum_memory; +int fps_count;// 2001-11-31 FPS display by QuakeForge/Muff + +client_t *host_client; // current client +#ifdef USEFPM +client_FPM_t *host_clientFPM; // current client +#endif + +jmp_buf host_abortserver; + +byte *host_basepal; +byte *host_colormap; + +cvar_t host_framerate = {"host_framerate","0"}; // set for slow motion +cvar_t host_speeds = {"host_speeds","0"}; // set for running times + +cvar_t sys_ticrate = {"sys_ticrate","0.05"}; +cvar_t serverprofile = {"serverprofile","0"}; + +cvar_t fraglimit = {"fraglimit","0",false,true}; +cvar_t timelimit = {"timelimit","0",false,true}; +cvar_t teamplay = {"teamplay","0",false,true}; + +cvar_t samelevel = {"samelevel","0"}; +cvar_t noexit = {"noexit","0",false,true}; + +#ifdef QUAKE2 +cvar_t developer = {"developer","1"}; // should be 0 for release! +#else +cvar_t developer = {"developer","0"}; +#endif + +cvar_t skill = {"skill","1"}; // 0 - 3 +cvar_t deathmatch = {"deathmatch","0"}; // 0, 1, or 2 +cvar_t coop = {"coop","0"}; // 0 or 1 + +cvar_t pausable = {"pausable","1"}; + +cvar_t temp1 = {"temp1","0"}; + + +/* +================ +Host_EndGame +================ +*/ +void Host_EndGame (char *message, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,message); + vsprintf (string,message,argptr); + va_end (argptr); + Con_DPrintf ("Host_EndGame: %s\n",string); + + if (sv.active) + Host_ShutdownServer (false); + + if (cls.state == ca_dedicated) + Sys_Error ("Host_EndGame: %s\n",string); // dedicated servers exit + + if (cls.demonum != -1) + CL_NextDemo (); + else + CL_Disconnect (); + + longjmp (host_abortserver, 1); +} + +/* +================ +Host_Error + +This shuts down both the client and server +================ +*/ +void Host_Error (char *error, ...) +{ + va_list argptr; + char string[1024]; + static qboolean inerror = false; + + if (inerror) + Sys_Error ("Host_Error: recursively entered"); + inerror = true; + + SCR_EndLoadingPlaque (); // reenable screen updates + + va_start (argptr,error); + vsprintf (string,error,argptr); + va_end (argptr); + Con_Printf ("Host_Error: %s\n",string); + + if (sv.active) + Host_ShutdownServer (false); + + if (cls.state == ca_dedicated) + Sys_Error ("Host_Error: %s\n",string); // dedicated servers exit + + CL_Disconnect (); + cls.demonum = -1; + + inerror = false; + + longjmp (host_abortserver, 1); +} + +/* +================ +Host_FindMaxClients +================ +*/ +void Host_FindMaxClients (void) +{ + int i; + + svs.maxclients = 1; + + i = COM_CheckParm ("-dedicated"); + if (i) + { + cls.state = ca_dedicated; + if (i != (com_argc - 1)) + { + svs.maxclients = Q_atoi (com_argv[i+1]); + } + else + svs.maxclients = 8; + } + else + cls.state = ca_disconnected; + + i = COM_CheckParm ("-listen"); + if (i) + { + if (cls.state == ca_dedicated) + Sys_Error ("Only one of -dedicated or -listen can be specified"); + if (i != (com_argc - 1)) + svs.maxclients = Q_atoi (com_argv[i+1]); + else + svs.maxclients = 8; + } + if (svs.maxclients < 1) + svs.maxclients = 8; + else if (svs.maxclients > MAX_SCOREBOARD) + svs.maxclients = MAX_SCOREBOARD; + + svs.maxclientslimit = svs.maxclients; + if (svs.maxclientslimit < 4) + svs.maxclientslimit = 4; + svs.clients = Hunk_AllocName (svs.maxclientslimit*sizeof(client_t), "clients"); + + if (svs.maxclients > 1) + Cvar_SetValue ("deathmatch", 1.0); + else + Cvar_SetValue ("deathmatch", 0.0); +} + + +/* +======================= +Host_InitLocal +====================== +*/ +void Host_InitLocal (void) +{ +#ifndef USEFPM + Host_InitCommands (); +#else + Host_InitCommandsFPM (); +#endif + + Cvar_RegisterVariable (&host_framerate); + Cvar_RegisterVariable (&host_speeds); + + Cvar_RegisterVariable (&sys_ticrate); + Cvar_RegisterVariable (&serverprofile); + + Cvar_RegisterVariable (&fraglimit); + Cvar_RegisterVariable (&timelimit); + Cvar_RegisterVariable (&teamplay); + Cvar_RegisterVariable (&samelevel); + Cvar_RegisterVariable (&noexit); + Cvar_RegisterVariable (&skill); + Cvar_RegisterVariable (&developer); + Cvar_RegisterVariable (&deathmatch); + Cvar_RegisterVariable (&coop); + + Cvar_RegisterVariable (&pausable); + + Cvar_RegisterVariable (&temp1); + + Host_FindMaxClients (); + + host_time = 1.0; // so a think at time 0 won't get called +} + + +/* +=============== +Host_WriteConfiguration + +Writes key bindings and archived cvars to config.cfg +=============== +*/ +void Host_WriteConfiguration (void) { + FILE *f; + +// dedicated servers initialize the host but don't parse and set the +// config.cfg cvars + if (host_initialized & !isDedicated) { + if (cl_config.value == 2) + f = fopen (va("%s/userconfig.cfg",com_gamedir), "w"); + + Con_Printf ("Config saved...\n"); + + if (!f) { + Con_Printf ("Couldn't write userconfig.cfg.\n"); + return; + } + + Key_WriteBindings (f); + Cvar_WriteVariables (f); + + fflush(f); + fclose (f); + sync(); + } +} + + +/* +================= +SV_ClientPrintf + +Sends text across to be displayed +FIXME: make this just a stuffed echo? +================= +*/ +void SV_ClientPrintf (char *fmt, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,fmt); + vsprintf (string, fmt,argptr); + va_end (argptr); + + MSG_WriteByte (&host_client->message, svc_print); + MSG_WriteString (&host_client->message, string); +} + +/* +================= +SV_BroadcastPrintf + +Sends text to all active clients +================= +*/ +void SV_BroadcastPrintf (char *fmt, ...) +{ + va_list argptr; + char string[1024]; + int i; + + va_start (argptr,fmt); + vsprintf (string, fmt,argptr); + va_end (argptr); + + for (i=0 ; imessage, svc_stufftext); + MSG_WriteString (&host_client->message, string); +} + +#ifdef USEFPM +void Host_ClientCommandsFPM (char *fmt, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,fmt); + vsprintf (string, fmt,argptr); + va_end (argptr); + + MSG_WriteByte (&host_clientFPM->message, svc_stufftext); + MSG_WriteString (&host_clientFPM->message, string); +} +#endif + +/* +===================== +SV_DropClient + +Called when the player is getting totally kicked off the host +if (crash = true), don't bother sending signofs +===================== +*/ +void SV_DropClient (qboolean crash) +{ + int saveSelf; + int i; + client_t *client; + + if (!crash) + { + // send any final messages (don't check for errors) + if (NET_CanSendMessage (host_client->netconnection)) + { + MSG_WriteByte (&host_client->message, svc_disconnect); + NET_SendMessage (host_client->netconnection, &host_client->message); + } + + if (host_client->edict && host_client->spawned) + { + // call the prog function for removing a client + // this will set the body to a dead frame, among other things + saveSelf = pr_global_struct->self; + pr_global_struct->self = EDICT_TO_PROG(host_client->edict); + PR_ExecuteProgram (pr_global_struct->ClientDisconnect); + pr_global_struct->self = saveSelf; + } + + Sys_Printf ("Client %s removed\n",host_client->name); + } + +// break the net connection + NET_Close (host_client->netconnection); + host_client->netconnection = NULL; + +// free the client (the body stays around) + host_client->active = false; + host_client->name[0] = 0; + host_client->old_frags = -999999; + net_activeconnections--; + +// send notification to all clients + for (i=0, client = svs.clients ; iactive) + continue; + MSG_WriteByte (&client->message, svc_updatename); + MSG_WriteByte (&client->message, host_client - svs.clients); + MSG_WriteString (&client->message, ""); + MSG_WriteByte (&client->message, svc_updatefrags); + MSG_WriteByte (&client->message, host_client - svs.clients); + MSG_WriteShort (&client->message, 0); + MSG_WriteByte (&client->message, svc_updatecolors); + MSG_WriteByte (&client->message, host_client - svs.clients); + MSG_WriteByte (&client->message, 0); + } +} + +#ifdef USEFPM +void SV_DropClientFPM (qboolean crash) +{ + int saveSelf; + int i; + client_FPM_t *client; + + if (!crash) + { + // send any final messages (don't check for errors) + if (NET_CanSendMessage (host_clientFPM->netconnection)) + { + MSG_WriteByte (&host_clientFPM->message, svc_disconnect); + NET_SendMessage (host_clientFPM->netconnection, &host_clientFPM->message); + } + + if (host_clientFPM->edict && host_clientFPM->spawned) + { + // call the prog function for removing a client + // this will set the body to a dead frame, among other things + saveSelf = pr_global_struct->self; + pr_global_struct->self = EDICT_TO_PROGFPM(host_clientFPM->edict); + PR_ExecuteProgramFPM (pr_global_struct->ClientDisconnect); + pr_global_struct->self = saveSelf; + } + + Sys_Printf ("Client %s removed\n",host_client->name); + } + +// break the net connection + NET_Close (host_client->netconnection); + host_clientFPM->netconnection = NULL; + +// free the client (the body stays around) + host_clientFPM->active = false; + host_clientFPM->name[0] = 0; + host_clientFPM->old_frags = -999999; + net_activeconnections--; + +// send notification to all clients + for (i=0, client = svsFPM.clients ; iactive) + continue; + MSG_WriteByte (&client->message, svc_updatename); + MSG_WriteByte (&client->message, host_clientFPM - svsFPM.clients); + MSG_WriteString (&client->message, ""); + MSG_WriteByte (&client->message, svc_updatefrags); + MSG_WriteByte (&client->message, host_clientFPM - svsFPM.clients); + MSG_WriteShort (&client->message, 0); + MSG_WriteByte (&client->message, svc_updatecolors); + MSG_WriteByte (&client->message, host_clientFPM - svsFPM.clients); + MSG_WriteByte (&client->message, 0); + } +} +#endif + +/* +================== +Host_ShutdownServer + +This only happens at the end of a game, not between levels +================== +*/ +void Host_ShutdownServer(qboolean crash) +{ + int i; + int count; + sizebuf_t buf; + char message[4]; + double start; + + if (!sv.active) + return; + + sv.active = false; + +// stop all client sounds immediately + if (cls.state == ca_connected) + CL_Disconnect (); + +// flush any pending messages - like the score!!! + start = Sys_FloatTime(); + do + { + count = 0; + for (i=0, host_client = svs.clients ; iactive && host_client->message.cursize) + { + if (NET_CanSendMessage (host_client->netconnection)) + { + NET_SendMessage(host_client->netconnection, &host_client->message); + SZ_Clear (&host_client->message); + } + else + { + NET_GetMessage(host_client->netconnection); + count++; + } + } + } + if ((Sys_FloatTime() - start) > 3.0) + break; + } + while (count); + +// make sure all the clients know we're disconnecting + buf.data = message; + buf.maxsize = 4; + buf.cursize = 0; + MSG_WriteByte(&buf, svc_disconnect); + count = NET_SendToAll(&buf, 5); + if (count) + Con_Printf("Host_ShutdownServer: NET_SendToAll failed for %u clients\n", count); + + for (i=0, host_client = svs.clients ; iactive) + SV_DropClient(crash); + +// +// clear structures +// + Q_memset (&sv, 0, sizeof(sv)); + Q_memset (svs.clients, 0, svs.maxclientslimit*sizeof(client_t)); +} + +#ifdef USEFPM +void Host_ShutdownServerFPM(qboolean crash) +{ + int i; + int count; + sizebuf_t buf; + char message[4]; + double start; + + if (!svFPM.active) + return; + + svFPM.active = false; + +// stop all client sounds immediately + if (cls.state == ca_connected) + CL_Disconnect (); + +// flush any pending messages - like the score!!! + start = Sys_FloatTime(); + do + { + count = 0; + for (i=0, host_client = svs.clients ; iactive && host_client->message.cursize) + { + if (NET_CanSendMessage (host_client->netconnection)) + { + NET_SendMessage(host_client->netconnection, &host_client->message); + SZ_Clear (&host_client->message); + } + else + { + NET_GetMessage(host_client->netconnection); + count++; + } + } + } + if ((Sys_FloatTime() - start) > 3.0) + break; + } + while (count); + +// make sure all the clients know we're disconnecting + buf.data = message; + buf.maxsize = 4; + buf.cursize = 0; + MSG_WriteByte(&buf, svc_disconnect); + count = NET_SendToAll(&buf, 5); + if (count) + Con_Printf("Host_ShutdownServer: NET_SendToAll failed for %u clients\n", count); + + for (i=0, host_client = svs.clients ; iactive) + SV_DropClient(crash); + +// +// clear structures +// + Q_memset (&sv, 0, sizeof(sv)); + Q_memset (svs.clients, 0, svs.maxclientslimit*sizeof(client_t)); +} +#endif + +/* +================ +Host_ClearMemory + +This clears all the memory used by both the client and server, but does +not reinitialize anything. +================ +*/ +void Host_ClearMemory (void) +{ + Con_DPrintf ("Clearing memory\n"); + D_FlushCaches (); + Mod_ClearAll (); + if (host_hunklevel) + Hunk_FreeToLowMark (host_hunklevel); + + cls.signon = 0; + Q_memset (&sv, 0, sizeof(sv)); + Q_memset (&cl, 0, sizeof(cl)); +} + +#ifdef USEFPM +void Host_ClearMemoryFPM (void) +{ + Con_DPrintf ("Clearing memory\n"); + D_FlushCachesFPM (); + Mod_ClearAllFPM (); + if (host_hunklevel) + Hunk_FreeToLowMark (host_hunklevel); + + cls.signon = 0; + Q_memset (&svFPM, 0, sizeof(svFPM)); + Q_memset (&clFPM, 0, sizeof(clFPM)); +} +#endif + +//============================================================================ + + +/* +=================== +Host_FilterTime + +Returns false if the time is too short to run a frame +=================== +*/ +qboolean Host_FilterTime (float time) +{ + realtime += time; + + if (!cls.timedemo && realtime - oldrealtime < 1.0/72.0) + return false; // framerate is too high + + host_frametime = realtime - oldrealtime; + oldrealtime = realtime; + + if (host_framerate.value > 0) + host_frametime = host_framerate.value; + else + { // don't allow really long or short frames + if (host_frametime > 0.1) + host_frametime = 0.1; + if (host_frametime < 0.001) + host_frametime = 0.001; + } + + return true; +} + + +/* +=================== +Host_GetConsoleCommands + +Add them exactly as if they had been typed at the console +=================== +*/ +void Host_GetConsoleCommands (void) +{ + char *cmd; + + while (1) + { + cmd = Sys_ConsoleInput (); + if (!cmd) + break; + Cbuf_AddText (cmd); + } +} + + +/* +================== +Host_ServerFrame + +================== +*/ +#ifdef FPS_20 +void _Host_ServerFrame (void) +{ +// run the world state + pr_global_struct->frametime = host_frametime; + +// read client messages + SV_RunClients (); + +// move things around and think +// always pause in single player if in console or menus + if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) ) + SV_Physics (); +} + +void Host_ServerFrame (void) +{ + float save_host_frametime; + float temp_host_frametime; + +// run the world state + pr_global_struct->frametime = host_frametime; + +// set the time and clear the general datagram + SV_ClearDatagram (); + +// check for new clients + SV_CheckForNewClients (); + + temp_host_frametime = save_host_frametime = host_frametime; + while(temp_host_frametime > (1.0/72.0)) + { + if (temp_host_frametime > 0.05) + host_frametime = 0.05; + else + host_frametime = temp_host_frametime; + temp_host_frametime -= host_frametime; + _Host_ServerFrame (); + } + host_frametime = save_host_frametime; + +// send all messages to the clients + SV_SendClientMessages (); +} + +#else + +void Host_ServerFrame (void) +{ +// run the world state + pr_global_struct->frametime = (float)host_frametime; + +// set the time and clear the general datagram + SV_ClearDatagram (); + +// check for new clients + SV_CheckForNewClients (); + +// read client messages + SV_RunClients (); + +// move things around and think +// always pause in single player if in console or menus + if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) ) + SV_Physics (); + +// send all messages to the clients + SV_SendClientMessages (); +} + +#endif + + +/* +================== +Host_Frame + +Runs all active servers +================== +*/ +void _Host_Frame (float time) +{ + static double time1 = 0; + static double time2 = 0; + static double time3 = 0; + int pass1, pass2, pass3; + + if (setjmp (host_abortserver) ) + return; // something bad happened, or the server disconnected + +// keep the random time dependent + rand (); + +// decide the simulation time + if (!Host_FilterTime (time)) + return; // don't run too fast, or packets will flood out + +// get new key events + Sys_SendKeyEvents (); + +// allow mice or other external controllers to add commands + IN_Commands (); + +// process console commands + Cbuf_Execute (); + + NET_Poll(); + +// if running the server locally, make intentions now + if (sv.active) + CL_SendCmd (); + +//------------------- +// +// server operations +// +//------------------- + +// check for commands typed to the host + Host_GetConsoleCommands (); + + if (sv.active) + Host_ServerFrame (); + +//------------------- +// +// client operations +// +//------------------- + +// if running the server remotely, send intentions now after +// the incoming messages have been read + if (!sv.active) + CL_SendCmd (); + + host_time += host_frametime; + +// fetch results from server + if (cls.state == ca_connected) + { +#ifdef USEFPM + CL_ReadFromServerFPM(); +#else + CL_ReadFromServer (); +#endif + } + +// update video + if (host_speeds.value) + time1 = Sys_FloatTime (); + SCR_UpdateScreen (); + + if (host_speeds.value) + time2 = Sys_FloatTime (); + +// update audio + if (cls.signon == SIGNONS) + { + S_Update (r_origin, vpn, vright, vup); +#ifdef USEFPM + CL_DecayLightsFPM (); +#else + CL_DecayLights (); +#endif + } + else + S_Update (vec3_origin, vec3_origin, vec3_origin, vec3_origin); + + CDAudio_Update(); + + if (host_speeds.value) + { + pass1 = (int)((time1 - time3)*1000); + time3 = Sys_FloatTime (); + pass2 = (int)((time2 - time1)*1000); + pass3 = (int)((time3 - time2)*1000); + Con_Printf ("%3i tot %3i server %3i gfx %3i snd\n", + pass1+pass2+pass3, pass1, pass2, pass3); + } + + host_framecount++; + fps_count++; +} + +void Host_Frame (float time) +{ + double time1, time2; + static double timetotal; + static int timecount; + int i, c, m; + + if (!serverprofile.value) + { + _Host_Frame (time); + return; + } + + time1 = Sys_FloatTime (); + _Host_Frame (time); + time2 = Sys_FloatTime (); + + timetotal += time2 - time1; + timecount++; + + if (timecount < 1000) + return; + + m = (int)(timetotal*1000/timecount); + timecount = 0; + timetotal = 0; + c = 0; + for (i=0 ; iargv[0]; + for (i = 0; i < com_argc; i++) + { + Sys_FileRead (vcrFile, &len, sizeof(int)); + p = malloc(len); + Sys_FileRead (vcrFile, p, len); + com_argv[i+1] = p; + } + com_argc++; /* add one for arg[0] */ + parms->argc = com_argc; + parms->argv = com_argv; + } + + if ( (n = COM_CheckParm("-record")) != 0) + { + vcrFile = Sys_FileOpenWrite("quake.vcr"); + + i = VCR_SIGNATURE; + Sys_FileWrite(vcrFile, &i, sizeof(int)); + i = com_argc - 1; + Sys_FileWrite(vcrFile, &i, sizeof(int)); + for (i = 1; i < com_argc; i++) + { + if (i == n) + { + len = 10; + Sys_FileWrite(vcrFile, &len, sizeof(int)); + Sys_FileWrite(vcrFile, "-playback", len); + continue; + } + len = Q_strlen(com_argv[i]) + 1; + Sys_FileWrite(vcrFile, &len, sizeof(int)); + Sys_FileWrite(vcrFile, com_argv[i], len); + } + sync(); + } + +} + +/* +==================== +Host_Init +==================== +*/ +void Host_Init (quakeparms_t *parms) { + if (standard_quake) + minimum_memory = MINIMUM_MEMORY; + else + minimum_memory = MINIMUM_MEMORY_LEVELPAK; + + if (COM_CheckParm ("-minmemory")) + parms->memsize = minimum_memory; + + host_parms = *parms; + + if (parms->memsize < minimum_memory) + Sys_Error ("Only %4.1f megs of memory available, can't execute game", parms->memsize / (float)0x100000); + + com_argc = parms->argc; + com_argv = parms->argv; + + Memory_Init (parms->membase, parms->memsize); + Cbuf_Init (); + Cmd_Init (); + V_Init (); + Chase_Init (); + Host_InitVCR (parms); + COM_Init (parms->basedir); + Host_InitLocal (); + + W_LoadWadFile ("gfx.wad"); + + Key_Init (); + Con_Init (); + M_Init (); + PR_Init (); + Mod_Init (); + puts("about to net init-"); + NET_Init (); + puts("net init done"); + SV_Init (); + + Con_Printf ("Exe: "__TIME__" "__DATE__"\n"); + Con_Printf ("%4.1f megabyte heap\n",parms->memsize/ (1024*1024.0)); + + R_InitTextures (); // needed even for dedicated servers + + if (cls.state != ca_dedicated) { + host_basepal = (byte *)COM_LoadHunkFile ("gfx/palette.lmp"); + if (!host_basepal) + Sys_Error ("Couldn't load gfx/palette.lmp"); + host_colormap = (byte *)COM_LoadHunkFile ("gfx/colormap.lmp"); + if (!host_colormap) + Sys_Error ("Couldn't load gfx/colormap.lmp"); + +#ifndef _WIN32 // on non win32, mouse comes before video for security reasons + IN_Init (); +#endif + + VID_Init (host_basepal); + COM_InitFilesystem (); // Addon load by R2-Tec + + //Dan + Draw_Init (); + SCR_Init (); +#ifdef USEFPM + R_InitFPM(); +#else + R_Init(); +#endif + +#ifndef _WIN32 + // on Win32, sound initialization has to come before video initialization, so we + // can put up a popup if the sound hardware is in use + S_Init (); +#else + +#ifdef GLQUAKE + // FIXME: doesn't use the new one-window approach yet + S_Init (); +#endif + +#endif // _WIN32 + CDAudio_Init (); + Sbar_Init (); + CL_Init (); +#ifdef _WIN32 // on non win32, mouse comes before video for security reasons + IN_Init (); +#endif + } + + Cbuf_InsertText ("cl_config 2;exec default.cfg;exec userconfig.cfg\n"); + Cbuf_InsertText ("startdemos demo1 demo2 demo3\n"); + + Hunk_AllocName (0, "-HOST_HUNKLEVEL-"); + host_hunklevel = Hunk_LowMark (); + + host_initialized = true; + + Sys_Printf ("========Quake Initialized=========\n"); +} + + +/* +=============== +Host_Shutdown + +FIXME: this is a callback from Sys_Quit and Sys_Error. It would be better +to run quit through here before the final handoff to the sys code. +=============== +*/ +void Host_Shutdown(void) +{ + static qboolean isdown = false; + + if (isdown) + { + printf ("recursive shutdown\n"); + return; + } + isdown = true; + +// keep Con_Printf from trying to update the screen + scr_disabled_for_loading = true; + + Host_WriteConfiguration (); + + CDAudio_Shutdown (); + NET_Shutdown (); + S_Shutdown(); + IN_Shutdown (); + + if (cls.state != ca_dedicated) + { + VID_Shutdown(); + } +} + diff --git a/project/jni/application/quake/source/host_cmd.c b/project/jni/application/quake/source/host_cmd.c new file mode 100644 index 000000000..0290df20f --- /dev/null +++ b/project/jni/application/quake/source/host_cmd.c @@ -0,0 +1,3450 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" + +extern cvar_t pausable; + +int current_skill; + +void Mod_Print (void); +#ifdef USEFPM +void Mod_PrintFPM (void); +#endif +/* +================== +Host_Quit_f +================== +*/ + +extern void M_Menu_Quit_f (void); + +void Host_Quit_f (void) +{ + if (key_dest != key_console && cls.state != ca_dedicated) + { + M_Menu_Quit_f (); + return; + } + CL_Disconnect (); + Host_ShutdownServer(false); + + Sys_Quit (); +} + +#ifdef USEFPM +void Host_Quit_FPM_f (void) +{ + if (key_dest != key_console && cls.state != ca_dedicated) + { + M_Menu_Quit_f (); + return; + } + CL_DisconnectFPM (); + Host_ShutdownServerFPM(false); + + Sys_Quit (); +} +#endif + +/* +================== +Host_Status_f +================== +*/ +void Host_Status_f (void) +{ + client_t *client; + int seconds; + int minutes; + int hours = 0; + int j; + void (*print) (char *fmt, ...); + + if (cmd_source == src_command) + { + if (!sv.active) + { + Cmd_ForwardToServer (); + return; + } + print = Con_Printf; + } + else + print = SV_ClientPrintf; + + print ("host: %s\n", Cvar_VariableString ("hostname")); + print ("version: %4.2f\n", VERSION); + if (tcpipAvailable) + print ("tcp/ip: %s\n", my_tcpip_address); + if (ipxAvailable) + print ("ipx: %s\n", my_ipx_address); + print ("map: %s\n", sv.name); + print ("players: %i active (%i max)\n\n", net_activeconnections, svs.maxclients); + for (j=0, client = svs.clients ; jactive) + continue; + seconds = (int)(net_time - client->netconnection->connecttime); + minutes = seconds / 60; + if (minutes) + { + seconds -= (minutes * 60); + hours = minutes / 60; + if (hours) + minutes -= (hours * 60); + } + else + hours = 0; + print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->v.frags, hours, minutes, seconds); + print (" %s\n", client->netconnection->address); + } +} + +#ifdef USEFPM +void Host_Status_FPM_f (void) +{ + client_FPM_t *client; + int seconds; + int minutes; + int hours = 0; + int j; + void (*print) (char *fmt, ...); + + if (cmd_source == src_command) + { + if (!svFPM.active) + { + Cmd_ForwardToServer (); + return; + } + print = Con_Printf; + } + else + print = SV_ClientPrintf; + + print ("host: %s\n", Cvar_VariableString ("hostname")); + print ("version: %4.2f\n", VERSION); + if (tcpipAvailable) + print ("tcp/ip: %s\n", my_tcpip_address); + if (ipxAvailable) + print ("ipx: %s\n", my_ipx_address); + print ("map: %s\n", sv.name); + print ("players: %i active (%i max)\n\n", net_activeconnections, svsFPM.maxclients); + for (j=0, client = svsFPM.clients ; jactive) + continue; + seconds = (int)(net_time - client->netconnection->connecttime); + minutes = seconds / 60; + if (minutes) + { + seconds -= (minutes * 60); + hours = minutes / 60; + if (hours) + minutes -= (hours * 60); + } + else + hours = 0; + print ("#%-2u %-16.16s %3i %2i:%02i:%02i\n", j+1, client->name, (int)client->edict->v.frags, hours, minutes, seconds); + print (" %s\n", client->netconnection->address); + } +} +#endif + +/* +================== +Host_God_f + +Sets client to godmode +================== +*/ +void Host_God_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_client->privileged) + return; + + sv_player->v.flags = (float)((int)sv_player->v.flags ^ FL_GODMODE); + if (!((int)sv_player->v.flags & FL_GODMODE) ) + SV_ClientPrintf ("godmode OFF\n"); + else + SV_ClientPrintf ("godmode ON\n"); +} + +#ifdef USEFPM +void Host_God_FPM_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_clientFPM->privileged) + return; + + sv_playerFPM->v.flags = (float)((int)sv_playerFPM->v.flags ^ FL_GODMODE); + if (!((int)sv_playerFPM->v.flags & FL_GODMODE) ) + SV_ClientPrintf ("godmode OFF\n"); + else + SV_ClientPrintf ("godmode ON\n"); +} +#endif + +void Host_Notarget_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_client->privileged) + return; + + sv_player->v.flags = (float)((int)sv_player->v.flags ^ FL_NOTARGET); + if (!((int)sv_player->v.flags & FL_NOTARGET) ) + SV_ClientPrintf ("notarget OFF\n"); + else + SV_ClientPrintf ("notarget ON\n"); +} + +#ifdef USEFPM +void Host_Notarget_FPM_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_clientFPM->privileged) + return; + + sv_playerFPM->v.flags = (float)((int)sv_playerFPM->v.flags ^ FL_NOTARGET); + if (!((int)sv_playerFPM->v.flags & FL_NOTARGET) ) + SV_ClientPrintf ("notarget OFF\n"); + else + SV_ClientPrintf ("notarget ON\n"); +} +#endif + +qboolean noclip_anglehack; + +void Host_Noclip_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_client->privileged) + return; + + if (sv_player->v.movetype != MOVETYPE_NOCLIP) + { + noclip_anglehack = true; + sv_player->v.movetype = MOVETYPE_NOCLIP; + SV_ClientPrintf ("noclip ON\n"); + } + else + { + noclip_anglehack = false; + sv_player->v.movetype = MOVETYPE_WALK; + SV_ClientPrintf ("noclip OFF\n"); + } +} + +#ifdef USEFPM +void Host_Noclip_FPM_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_clientFPM->privileged) + return; + + if (sv_playerFPM->v.movetype != MOVETYPE_NOCLIP) + { + noclip_anglehack = true; + sv_playerFPM->v.movetype = MOVETYPE_NOCLIP; + SV_ClientPrintf ("noclip ON\n"); + } + else + { + noclip_anglehack = false; + sv_playerFPM->v.movetype = MOVETYPE_WALK; + SV_ClientPrintf ("noclip OFF\n"); + } +} +#endif + +/* +================== +Host_Fly_f + +Sets client to flymode +================== +*/ +void Host_Fly_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_client->privileged) + return; + + if (sv_player->v.movetype != MOVETYPE_FLY) + { + sv_player->v.movetype = MOVETYPE_FLY; + SV_ClientPrintf ("flymode ON\n"); + } + else + { + sv_player->v.movetype = MOVETYPE_WALK; + SV_ClientPrintf ("flymode OFF\n"); + } +} + +#ifdef USEFPM +void Host_Fly_FPM_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_clientFPM->privileged) + return; + + if (sv_playerFPM->v.movetype != MOVETYPE_FLY) + { + sv_playerFPM->v.movetype = MOVETYPE_FLY; + SV_ClientPrintf ("flymode ON\n"); + } + else + { + sv_playerFPM->v.movetype = MOVETYPE_WALK; + SV_ClientPrintf ("flymode OFF\n"); + } +} +#endif + +/* +================== +Host_Ping_f + +================== +*/ +void Host_Ping_f (void) +{ + int i, j; + float total; + client_t *client; + + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + SV_ClientPrintf ("Client ping times:\n"); + for (i=0, client = svs.clients ; iactive) + continue; + total = 0; + for (j=0 ; jping_times[j]; + total /= NUM_PING_TIMES; + SV_ClientPrintf ("%4i %s\n", (int)(total*1000), client->name); + } +} + +#ifdef USEFPM +void Host_Ping_FPM_f (void) +{ + int i, j; + float total; + client_FPM_t *client; + + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + SV_ClientPrintf ("Client ping times:\n"); + for (i=0, client = svsFPM.clients ; iactive) + continue; + total = 0; + for (j=0 ; jping_times[j]; + total /= NUM_PING_TIMES; + SV_ClientPrintf ("%4i %s\n", (int)(total*1000), client->name); + } +} +#endif + +/* +=============================================================================== + +SERVER TRANSITIONS + +=============================================================================== +*/ + + +/* +====================== +Host_Map_f + +handle a +map +command from the console. Active clients are kicked off. +====================== +*/ +void Host_Map_f (void) +{ + int i; + char name[MAX_QPATH]; + + if (cmd_source != src_command) + return; + + cls.demonum = -1; // stop demo loop in case this fails + + CL_Disconnect (); + Host_ShutdownServer(false); + + key_dest = key_game; // remove console or menu + SCR_BeginLoadingPlaque (); + + cls.mapstring[0] = 0; + for (i=0 ; i : continue game on a new level\n"); + return; + } + if (!sv.active || cls.demoplayback) + { + Con_Printf ("Only the server may changelevel\n"); + return; + } + + strcpy (level, Cmd_Argv(1)); + if (Cmd_Argc() == 2) + startspot = NULL; + else + { + strcpy (_startspot, Cmd_Argv(2)); + startspot = _startspot; + } + + SV_SaveSpawnparms (); + SV_SpawnServer (level, startspot); +#else + char level[MAX_QPATH]; + + if (Cmd_Argc() != 2) + { + Con_Printf ("changelevel : continue game on a new level\n"); + return; + } + if (!sv.active || cls.demoplayback) + { + Con_Printf ("Only the server may changelevel\n"); + return; + } + SV_SaveSpawnparms (); + strcpy (level, Cmd_Argv(1)); + SV_SpawnServer (level); +#endif +} + +#ifdef USEFPM +void Host_Changelevel_FPM_f (void) +{ +#ifdef QUAKE2 + char level[MAX_QPATH]; + char _startspot[MAX_QPATH]; + char *startspot; + + if (Cmd_Argc() < 2) + { + Con_Printf ("changelevel : continue game on a new level\n"); + return; + } + if (!svFPM.active || cls.demoplayback) + { + Con_Printf ("Only the server may changelevel\n"); + return; + } + + strcpy (level, Cmd_Argv(1)); + if (Cmd_Argc() == 2) + startspot = NULL; + else + { + strcpy (_startspot, Cmd_Argv(2)); + startspot = _startspot; + } + + SV_SaveSpawnparmsFPM (); + SV_SpawnServerFPM (level, startspot); +#else + char level[MAX_QPATH]; + + if (Cmd_Argc() != 2) + { + Con_Printf ("changelevel : continue game on a new level\n"); + return; + } + if (!svFPM.active || cls.demoplayback) + { + Con_Printf ("Only the server may changelevel\n"); + return; + } + SV_SaveSpawnparmsFPM (); + strcpy (level, Cmd_Argv(1)); + SV_SpawnServerFPM (level); +#endif +} +#endif + +/* +================== +Host_Restart_f + +Restarts the current server for a dead player +================== +*/ +void Host_Restart_f (void) +{ + char mapname[MAX_QPATH]; +#ifdef QUAKE2 + char startspot[MAX_QPATH]; +#endif + + if (cls.demoplayback || !sv.active) + return; + + if (cmd_source != src_command) + return; + strcpy (mapname, sv.name); // must copy out, because it gets cleared + // in sv_spawnserver +#ifdef QUAKE2 + strcpy(startspot, sv.startspot); + SV_SpawnServer (mapname, startspot); +#else + SV_SpawnServer (mapname); +#endif +} + +#ifdef USEFPM +void Host_Restart_FPM_f (void) +{ + char mapname[MAX_QPATH]; +#ifdef QUAKE2 + char startspot[MAX_QPATH]; +#endif + + if (cls.demoplayback || !svFPM.active) + return; + + if (cmd_source != src_command) + return; + strcpy (mapname, svFPM.name); // must copy out, because it gets cleared + // in sv_spawnserver +#ifdef QUAKE2 + strcpy(startspot, svFPM.startspot); + SV_SpawnServerFPM (mapname, startspot); +#else + SV_SpawnServerFPM (mapname); +#endif +} +#endif + +/* +================== +Host_Reconnect_f + +This command causes the client to wait for the signon messages again. +This is sent just before a server changes levels +================== +*/ +void Host_Reconnect_f (void) +{ + SCR_BeginLoadingPlaque (); + cls.signon = 0; // need new connection messages +} + +#ifdef USEFPM +void Host_Reconnect_FPM_f (void) +{ + SCR_BeginLoadingPlaque (); + cls.signon = 0; // need new connection messages +} +#endif + +/* +===================== +Host_Connect_f + +User command to connect to server +===================== +*/ +void Host_Connect_f (void) +{ + char name[MAX_QPATH]; + + cls.demonum = -1; // stop demo loop in case this fails + if (cls.demoplayback) + { + CL_StopPlayback (); + CL_Disconnect (); + } + strcpy (name, Cmd_Argv(1)); + CL_EstablishConnection (name); + Host_Reconnect_f (); +} + +#ifdef USEFPM +void Host_Connect_FPM_f (void) +{ + char name[MAX_QPATH]; + + cls.demonum = -1; // stop demo loop in case this fails + if (cls.demoplayback) + { + CL_StopPlayback (); + CL_DisconnectFPM (); + } + strcpy (name, Cmd_Argv(1)); + CL_EstablishConnection (name); + Host_Reconnect_FPM_f (); +} +#endif +/* +=============================================================================== + +LOAD / SAVE GAME + +=============================================================================== +*/ + +#define SAVEGAME_VERSION 5 + +/* +=============== +Host_SavegameComment + +Writes a SAVEGAME_COMMENT_LENGTH character comment describing the current +=============== +*/ +void Host_SavegameComment (char *text) +{ + int i; + char kills[20]; + + for (i=0 ; i : save a game\n"); + return; + } + + if (strstr(Cmd_Argv(1), "..")) + { + Con_Printf ("Relative pathnames are not allowed.\n"); + return; + } + + for (i=0 ; iv.health <= 0) ) + { + Con_Printf ("Can't savegame with a dead player\n"); + return; + } + } + + sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); + COM_DefaultExtension (name, ".sav"); + + Con_Printf ("Saving game to %s...\n", name); + f = fopen (name, "w"); + if (!f) + { + Con_Printf ("ERROR: couldn't open.\n"); + return; + } + + fprintf (f, "%i\n", SAVEGAME_VERSION); + Host_SavegameComment (comment); + fprintf (f, "%s\n", comment); + for (i=0 ; ispawn_parms[i]); + fprintf (f, "%d\n", current_skill); + fprintf (f, "%s\n", sv.name); + fprintf (f, "%f\n",sv.time); + +// write the light styles + + for (i=0 ; i : save a game\n"); + return; + } + + if (strstr(Cmd_Argv(1), "..")) + { + Con_Printf ("Relative pathnames are not allowed.\n"); + return; + } + + for (i=0 ; iv.health <= 0) ) + { + Con_Printf ("Can't savegame with a dead player\n"); + return; + } + } + + sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); + COM_DefaultExtension (name, ".sav"); + + Con_Printf ("Saving game to %s...\n", name); + f = fopen (name, "w"); + if (!f) + { + Con_Printf ("ERROR: couldn't open.\n"); + return; + } + + fprintf (f, "%i\n", SAVEGAME_VERSION); + Host_SavegameComment (comment); + fprintf (f, "%s\n", comment); + for (i=0 ; ispawn_parms[i]); + fprintf (f, "%d\n", current_skill); + fprintf (f, "%s\n", sv.name); + fprintf (f, "%f\n",sv.time); + +// write the light styles + + for (i=0 ; i : load a game\n"); + return; + } + + cls.demonum = -1; // stop demo loop in case this fails + + sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); + COM_DefaultExtension (name, ".sav"); + +// we can't call SCR_BeginLoadingPlaque, because too much stack space has +// been used. The menu calls it before stuffing loadgame command +// SCR_BeginLoadingPlaque (); + + Con_Printf ("Loading game from %s...\n", name); + f = fopen (name, "r"); + if (!f) + { + Con_Printf ("ERROR: couldn't open.\n"); + return; + } + + fscanf (f, "%i\n", &version); + if (version != SAVEGAME_VERSION) + { + fclose (f); + Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); + return; + } + fscanf (f, "%s\n", str); + for (i=0 ; iv, 0, progs->entityfields * 4); + ent->free = false; + ED_ParseEdict (start, ent); + + // link it into the bsp tree + if (!ent->free) + SV_LinkEdict (ent, false); + } + + entnum++; + } + + sv.num_edicts = entnum; + sv.time = time; + + fclose (f); + + for (i=0 ; ispawn_parms[i] = spawn_parms[i]; + + if (cls.state != ca_dedicated) + { + CL_EstablishConnection ("local"); + Host_Reconnect_f (); + } +} + +#ifdef USEFPM +void Host_Loadgame_FPM_f (void) +{ + char name[MAX_OSPATH]; + FILE *f; + char mapname[MAX_QPATH]; + float time, tfloat; + char str[32768], *start; + int i, r; + edict_FPM_t *ent; + int entnum; + int version; + float spawn_parms[NUM_SPAWN_PARMS]; + + if (cmd_source != src_command) + return; + + if (Cmd_Argc() != 2) + { + Con_Printf ("load : load a game\n"); + return; + } + + cls.demonum = -1; // stop demo loop in case this fails + + sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); + COM_DefaultExtension (name, ".sav"); + +// we can't call SCR_BeginLoadingPlaque, because too much stack space has +// been used. The menu calls it before stuffing loadgame command +// SCR_BeginLoadingPlaque (); + + Con_Printf ("Loading game from %s...\n", name); + f = fopen (name, "r"); + if (!f) + { + Con_Printf ("ERROR: couldn't open.\n"); + return; + } + + fscanf (f, "%i\n", &version); + if (version != SAVEGAME_VERSION) + { + fclose (f); + Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); + return; + } + fscanf (f, "%s\n", str); + for (i=0 ; iv, 0, progs->entityfields * 4); + ent->free = false; + ED_ParseEdictFPM (start, ent); + + // link it into the bsp tree + if (!ent->free) + SV_LinkEdictFPM (ent, false); + } + + entnum++; + } + + svFPM.num_edicts = entnum; + svFPM.time = time; + + fclose (f); + + for (i=0 ; ispawn_parms[i] = spawn_parms[i]; + + if (cls.state != ca_dedicated) + { + CL_EstablishConnectionFPM ("local"); + Host_Reconnect_FPM_f (); + } +} +#endif + +#ifdef QUAKE2 +void SaveGamestate() +{ + char name[256]; + FILE *f; + int i; + char comment[SAVEGAME_COMMENT_LENGTH+1]; + edict_t *ent; + + sprintf (name, "%s/%s.gip", com_gamedir, sv.name); + + Con_Printf ("Saving game to %s...\n", name); + f = fopen (name, "w"); + if (!f) + { + Con_Printf ("ERROR: couldn't open.\n"); + return; + } + + fprintf (f, "%i\n", SAVEGAME_VERSION); + Host_SavegameComment (comment); + fprintf (f, "%s\n", comment); +// for (i=0 ; ispawn_parms[i]); + fprintf (f, "%f\n", skill.value); + fprintf (f, "%s\n", sv.name); + fprintf (f, "%f\n", sv.time); + +// write the light styles + + for (i=0 ; iv.flags & FL_ARCHIVE_OVERRIDE) + continue; + fprintf (f, "%i\n",i); + ED_Write (f, ent); + fflush (f); + } + fclose (f); + sync(); + Con_Printf ("done.\n"); +} + +int LoadGamestate(char *level, char *startspot) +{ + char name[MAX_OSPATH]; + FILE *f; + char mapname[MAX_QPATH]; + float time, sk; + char str[32768], *start; + int i, r; + edict_t *ent; + int entnum; + int version; +// float spawn_parms[NUM_SPAWN_PARMS]; + + sprintf (name, "%s/%s.gip", com_gamedir, level); + + Con_Printf ("Loading game from %s...\n", name); + f = fopen (name, "r"); + if (!f) + { + Con_Printf ("ERROR: couldn't open.\n"); + return -1; + } + + fscanf (f, "%i\n", &version); + if (version != SAVEGAME_VERSION) + { + fclose (f); + Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); + return -1; + } + fscanf (f, "%s\n", str); +// for (i=0 ; iv, 0, progs->entityfields * 4); + ent->free = false; + ED_ParseEdict (start, ent); + + // link it into the bsp tree + if (!ent->free) + SV_LinkEdict (ent, false); + } + +// sv.num_edicts = entnum; + sv.time = time; + fclose (f); + +// for (i=0 ; ispawn_parms[i] = spawn_parms[i]; + + return 0; +} + +// changing levels within a unit +void Host_Changelevel2_f (void) +{ + char level[MAX_QPATH]; + char _startspot[MAX_QPATH]; + char *startspot; + + if (Cmd_Argc() < 2) + { + Con_Printf ("changelevel2 : continue game on a new level in the unit\n"); + return; + } + if (!sv.active || cls.demoplayback) + { + Con_Printf ("Only the server may changelevel\n"); + return; + } + + strcpy (level, Cmd_Argv(1)); + if (Cmd_Argc() == 2) + startspot = NULL; + else + { + strcpy (_startspot, Cmd_Argv(2)); + startspot = _startspot; + } + + SV_SaveSpawnparms (); + + // save the current level's state + SaveGamestate (); + + // try to restore the new level + if (LoadGamestate (level, startspot)) + SV_SpawnServer (level, startspot); +} +#endif + + +//============================================================================ + +/* +====================== +Host_Name_f +====================== +*/ +void Host_Name_f (void) +{ + char *newName; + + if (Cmd_Argc () == 1) + { + Con_Printf ("\"name\" is \"%s\"\n", cl_name.string); + return; + } + if (Cmd_Argc () == 2) + newName = Cmd_Argv(1); + else + newName = Cmd_Args(); + newName[15] = 0; + + if (cmd_source == src_command) + { + if (Q_strcmp(cl_name.string, newName) == 0) + return; + Cvar_Set ("_cl_name", newName); + if (cls.state == ca_connected) + Cmd_ForwardToServer (); + return; + } + + if (host_client->name[0] && strcmp(host_client->name, "unconnected") ) + if (Q_strcmp(host_client->name, newName) != 0) + Con_Printf ("%s renamed to %s\n", host_client->name, newName); + Q_strcpy (host_client->name, newName); + host_client->edict->v.netname = host_client->name - pr_strings; + +// send notification to all clients + + MSG_WriteByte (&sv.reliable_datagram, svc_updatename); + MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients); + MSG_WriteString (&sv.reliable_datagram, host_client->name); +} + +#ifdef USEFPM +void Host_Name_FPM_f (void) +{ + char *newName; + + if (Cmd_Argc () == 1) + { + Con_Printf ("\"name\" is \"%s\"\n", cl_name.string); + return; + } + if (Cmd_Argc () == 2) + newName = Cmd_Argv(1); + else + newName = Cmd_Args(); + newName[15] = 0; + + if (cmd_source == src_command) + { + if (Q_strcmp(cl_name.string, newName) == 0) + return; + Cvar_Set ("_cl_name", newName); + if (cls.state == ca_connected) + Cmd_ForwardToServer (); + return; + } + + if (host_clientFPM->name[0] && strcmp(host_clientFPM->name, "unconnected") ) + if (Q_strcmp(host_clientFPM->name, newName) != 0) + Con_Printf ("%s renamed to %s\n", host_clientFPM->name, newName); + Q_strcpy (host_clientFPM->name, newName); + host_clientFPM->edict->v.netname = host_clientFPM->name - pr_strings; + +// send notification to all clients + + MSG_WriteByte (&svFPM.reliable_datagram, svc_updatename); + MSG_WriteByte (&svFPM.reliable_datagram, host_clientFPM - svsFPM.clients); + MSG_WriteString (&svFPM.reliable_datagram, host_clientFPM->name); +} +#endif + +void Host_Version_f (void) +{ + Con_Printf ("Version %4.2f\n", VERSION); + Con_Printf ("Exe: "__TIME__" "__DATE__"\n"); +} + +#ifdef USEFPM +void Host_Version_FPM_f (void) +{ + Con_Printf ("Version %4.2f\n", VERSION); + Con_Printf ("Exe: "__TIME__" "__DATE__"\n"); +} +#endif + +#ifdef IDGODS +void Host_Please_f (void) +{ + client_t *cl; + int j; + + if (cmd_source != src_command) + return; + + if ((Cmd_Argc () == 3) && Q_strcmp(Cmd_Argv(1), "#") == 0) + { + j = Q_atof(Cmd_Argv(2)) - 1; + if (j < 0 || j >= svs.maxclients) + return; + if (!svs.clients[j].active) + return; + cl = &svs.clients[j]; + if (cl->privileged) + { + cl->privileged = false; + cl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET); + cl->edict->v.movetype = MOVETYPE_WALK; + noclip_anglehack = false; + } + else + cl->privileged = true; + } + + if (Cmd_Argc () != 2) + return; + + for (j=0, cl = svs.clients ; jactive) + continue; + if (Q_strcasecmp(cl->name, Cmd_Argv(1)) == 0) + { + if (cl->privileged) + { + cl->privileged = false; + cl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET); + cl->edict->v.movetype = MOVETYPE_WALK; + noclip_anglehack = false; + } + else + cl->privileged = true; + break; + } + } +} + +#ifdef USEFPM +void Host_Please_FPM_f (void) +{ + client_FPM_t *cl; + int j; + + if (cmd_source != src_command) + return; + + if ((Cmd_Argc () == 3) && Q_strcmp(Cmd_Argv(1), "#") == 0) + { + j = Q_atof(Cmd_Argv(2)) - 1; + if (j < 0 || j >= svsFPM.maxclients) + return; + if (!svsFPM.clients[j].active) + return; + cl = &svsFPM.clients[j]; + if (cl->privileged) + { + cl->privileged = false; + cl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET); + cl->edict->v.movetype = MOVETYPE_WALK; + noclip_anglehack = false; + } + else + cl->privileged = true; + } + + if (Cmd_Argc () != 2) + return; + + for (j=0, cl = svsFPM.clients ; jactive) + continue; + if (Q_strcasecmp(cl->name, Cmd_Argv(1)) == 0) + { + if (cl->privileged) + { + cl->privileged = false; + cl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET); + cl->edict->v.movetype = MOVETYPE_WALK; + noclip_anglehack = false; + } + else + cl->privileged = true; + break; + } + } +} +#endif +#endif + + +void Host_Say(qboolean teamonly) +{ + client_t *client; + client_t *save; + int j; + char *p; + unsigned char text[64]; + qboolean fromServer = false; + + if (cmd_source == src_command) + { + if (cls.state == ca_dedicated) + { + fromServer = true; + teamonly = false; + } + else + { + Cmd_ForwardToServer (); + return; + } + } + + if (Cmd_Argc () < 2) + return; + + save = host_client; + + p = Cmd_Args(); +// remove quotes if present + if (*p == '"') + { + p++; + p[Q_strlen(p)-1] = 0; + } + +// turn on color set 1 + if (!fromServer) + sprintf (text, "%c%s: ", 1, save->name); + else + sprintf (text, "%c<%s> ", 1, hostname.string); + + j = sizeof(text) - 2 - Q_strlen(text); // -2 for /n and null terminator + if (Q_strlen(p) > j) + p[j] = 0; + + strcat (text, p); + strcat (text, "\n"); + + for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) + { + if (!client || !client->active || !client->spawned) + continue; + if (teamplay.value && teamonly && client->edict->v.team != save->edict->v.team) + continue; + host_client = client; + SV_ClientPrintf("%s", text); + } + host_client = save; + + Sys_Printf("%s", &text[1]); +} + +#ifdef USEFPM +void Host_SayFPM(qboolean teamonly) +{ + client_FPM_t *client; + client_FPM_t *save; + int j; + char *p; + unsigned char text[64]; + qboolean fromServer = false; + + if (cmd_source == src_command) + { + if (cls.state == ca_dedicated) + { + fromServer = true; + teamonly = false; + } + else + { + Cmd_ForwardToServer (); + return; + } + } + + if (Cmd_Argc () < 2) + return; + + save = host_clientFPM; + + p = Cmd_Args(); +// remove quotes if present + if (*p == '"') + { + p++; + p[Q_strlen(p)-1] = 0; + } + +// turn on color set 1 + if (!fromServer) + sprintf (text, "%c%s: ", 1, save->name); + else + sprintf (text, "%c<%s> ", 1, hostname.string); + + j = sizeof(text) - 2 - Q_strlen(text); // -2 for /n and null terminator + if (Q_strlen(p) > j) + p[j] = 0; + + strcat (text, p); + strcat (text, "\n"); + + for (j = 0, client = svsFPM.clients; j < svsFPM.maxclients; j++, client++) + { + if (!client || !client->active || !client->spawned) + continue; + if (teamplay.value && teamonly && client->edict->v.team != save->edict->v.team) + continue; + host_clientFPM = client; + SV_ClientPrintf("%s", text); + } + host_clientFPM = save; + + Sys_Printf("%s", &text[1]); +} +#endif + +void Host_Say_f(void) +{ + Host_Say(false); +} + +#ifdef USEFPM +void Host_Say_FPM_f(void) +{ + Host_SayFPM(false); +} +#endif + +void Host_Say_Team_f(void) +{ + Host_Say(true); +} + +#ifdef USEFPM +void Host_Say_Team_FPM_f(void) +{ + Host_SayFPM(true); +} +#endif + +void Host_Tell_f(void) +{ + client_t *client; + client_t *save; + int j; + char *p; + char text[64]; + + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (Cmd_Argc () < 3) + return; + + Q_strcpy(text, host_client->name); + Q_strcat(text, ": "); + + p = Cmd_Args(); + +// remove quotes if present + if (*p == '"') + { + p++; + p[Q_strlen(p)-1] = 0; + } + +// check length & truncate if necessary + j = sizeof(text) - 2 - Q_strlen(text); // -2 for /n and null terminator + if (Q_strlen(p) > j) + p[j] = 0; + + strcat (text, p); + strcat (text, "\n"); + + save = host_client; + for (j = 0, client = svs.clients; j < svs.maxclients; j++, client++) + { + if (!client->active || !client->spawned) + continue; + if (Q_strcasecmp(client->name, Cmd_Argv(1))) + continue; + host_client = client; + SV_ClientPrintf("%s", text); + break; + } + host_client = save; +} + +#ifdef USEFPM +void Host_Tell_FPM_f(void) +{ + client_FPM_t *client; + client_FPM_t *save; + int j; + char *p; + char text[64]; + + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (Cmd_Argc () < 3) + return; + + Q_strcpy(text, host_clientFPM->name); + Q_strcat(text, ": "); + + p = Cmd_Args(); + +// remove quotes if present + if (*p == '"') + { + p++; + p[Q_strlen(p)-1] = 0; + } + +// check length & truncate if necessary + j = sizeof(text) - 2 - Q_strlen(text); // -2 for /n and null terminator + if (Q_strlen(p) > j) + p[j] = 0; + + strcat (text, p); + strcat (text, "\n"); + + save = host_clientFPM; + for (j = 0, client = svsFPM.clients; j < svsFPM.maxclients; j++, client++) + { + if (!client->active || !client->spawned) + continue; + if (Q_strcasecmp(client->name, Cmd_Argv(1))) + continue; + host_clientFPM = client; + SV_ClientPrintf("%s", text); + break; + } + host_clientFPM = save; +} +#endif + +/* +================== +Host_Color_f +================== +*/ +void Host_Color_f(void) +{ + int top, bottom; + int playercolor; + + if (Cmd_Argc() == 1) + { + Con_Printf ("\"color\" is \"%i %i\"\n", ((int)cl_color.value) >> 4, ((int)cl_color.value) & 0x0f); + Con_Printf ("color <0-13> [0-13]\n"); + return; + } + + if (Cmd_Argc() == 2) + top = bottom = atoi(Cmd_Argv(1)); + else + { + top = atoi(Cmd_Argv(1)); + bottom = atoi(Cmd_Argv(2)); + } + + top &= 15; + if (top > 13) + top = 13; + bottom &= 15; + if (bottom > 13) + bottom = 13; + + playercolor = top*16 + bottom; + + if (cmd_source == src_command) + { + Cvar_SetValue ("_cl_color", (float)playercolor); + if (cls.state == ca_connected) + Cmd_ForwardToServer (); + return; + } + + host_client->colors = playercolor; + host_client->edict->v.team = (float)(bottom + 1); + +// send notification to all clients + MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors); + MSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients); + MSG_WriteByte (&sv.reliable_datagram, host_client->colors); +} + +#ifdef USEFPM +void Host_Color_FPM_f(void) +{ + int top, bottom; + int playercolor; + + if (Cmd_Argc() == 1) + { + Con_Printf ("\"color\" is \"%i %i\"\n", ((int)cl_color.value) >> 4, ((int)cl_color.value) & 0x0f); + Con_Printf ("color <0-13> [0-13]\n"); + return; + } + + if (Cmd_Argc() == 2) + top = bottom = atoi(Cmd_Argv(1)); + else + { + top = atoi(Cmd_Argv(1)); + bottom = atoi(Cmd_Argv(2)); + } + + top &= 15; + if (top > 13) + top = 13; + bottom &= 15; + if (bottom > 13) + bottom = 13; + + playercolor = top*16 + bottom; + + if (cmd_source == src_command) + { + Cvar_SetValue ("_cl_color", (float)playercolor); + if (cls.state == ca_connected) + Cmd_ForwardToServer (); + return; + } + + host_clientFPM->colors = playercolor; + host_clientFPM->edict->v.team = (float)(bottom + 1); + +// send notification to all clients + MSG_WriteByte (&svFPM.reliable_datagram, svc_updatecolors); + MSG_WriteByte (&svFPM.reliable_datagram, host_clientFPM - svsFPM.clients); + MSG_WriteByte (&svFPM.reliable_datagram, host_clientFPM->colors); +} +#endif + +/* +================== +Host_Kill_f +================== +*/ +void Host_Kill_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (sv_player->v.health <= 0) + { + SV_ClientPrintf ("Can't suicide -- allready dead!\n"); + return; + } + + pr_global_struct->time = (float)sv.time; + pr_global_struct->self = EDICT_TO_PROG(sv_player); + PR_ExecuteProgram (pr_global_struct->ClientKill); +} + +#ifdef USEFPM +void Host_Kill_FPM_f (void) +{ + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (sv_playerFPM->v.health <= 0) + { + SV_ClientPrintf ("Can't suicide -- allready dead!\n"); + return; + } + + pr_global_struct->time = (float)svFPM.time; + pr_global_struct->self = EDICT_TO_PROGFPM(sv_playerFPM); + PR_ExecuteProgramFPM(pr_global_struct->ClientKill); +} +#endif + +/* +================== +Host_Pause_f +================== +*/ +void Host_Pause_f (void) +{ + + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + if (!pausable.value) + SV_ClientPrintf ("Pause not allowed.\n"); + else + { + sv.paused ^= 1; + + if (sv.paused) + { + SV_BroadcastPrintf ("%s paused the game\n", pr_strings + sv_player->v.netname); + } + else + { + SV_BroadcastPrintf ("%s unpaused the game\n",pr_strings + sv_player->v.netname); + } + + // send notification to all clients + MSG_WriteByte (&sv.reliable_datagram, svc_setpause); + MSG_WriteByte (&sv.reliable_datagram, sv.paused); + } +} + +#ifdef USEFPM +void Host_Pause_FPM_f (void) +{ + + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + if (!pausable.value) + SV_ClientPrintf ("Pause not allowed.\n"); + else + { + svFPM.paused ^= 1; + + if (svFPM.paused) + { + SV_BroadcastPrintf ("%s paused the game\n", pr_strings + sv_playerFPM->v.netname); + } + else + { + SV_BroadcastPrintf ("%s unpaused the game\n",pr_strings + sv_playerFPM->v.netname); + } + + // send notification to all clients + MSG_WriteByte (&svFPM.reliable_datagram, svc_setpause); + MSG_WriteByte (&svFPM.reliable_datagram, svFPM.paused); + } +} +#endif + +//=========================================================================== + + +/* +================== +Host_PreSpawn_f +================== +*/ +void Host_PreSpawn_f (void) +{ + if (cmd_source == src_command) + { + Con_Printf ("prespawn is not valid from the console\n"); + return; + } + + if (host_client->spawned) + { + Con_Printf ("prespawn not valid -- allready spawned\n"); + return; + } + + SZ_Write (&host_client->message, sv.signon.data, sv.signon.cursize); + MSG_WriteByte (&host_client->message, svc_signonnum); + MSG_WriteByte (&host_client->message, 2); + host_client->sendsignon = true; +} + +#ifdef USEFPM +void Host_PreSpawn_FPM_f (void) +{ + if (cmd_source == src_command) + { + Con_Printf ("prespawn is not valid from the console\n"); + return; + } + + if (host_clientFPM->spawned) + { + Con_Printf ("prespawn not valid -- allready spawned\n"); + return; + } + + SZ_Write (&host_clientFPM->message, svFPM.signon.data, svFPM.signon.cursize); + MSG_WriteByte (&host_clientFPM->message, svc_signonnum); + MSG_WriteByte (&host_clientFPM->message, 2); + host_clientFPM->sendsignon = true; +} +#endif + +/* +================== +Host_Spawn_f +================== +*/ +void Host_Spawn_f (void) +{ + int i; + client_t *client; + edict_t *ent; + + if (cmd_source == src_command) + { + Con_Printf ("spawn is not valid from the console\n"); + return; + } + + if (host_client->spawned) + { + Con_Printf ("Spawn not valid -- allready spawned\n"); + return; + } + +// run the entrance script + if (sv.loadgame) + { // loaded games are fully inited allready + // if this is the last client to be connected, unpause + sv.paused = false; + } else { + // set up the edict + ent = host_client->edict; + + Q_memset (&ent->v, 0, progs->entityfields * 4); + ent->v.colormap = (float)NUM_FOR_EDICT(ent); + ent->v.team = (float)((host_client->colors & 15) + 1); + ent->v.netname = host_client->name - pr_strings; + + // copy spawn parms out of the client_t + + for (i=0 ; i< NUM_SPAWN_PARMS ; i++) + (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i]; + + // call the spawn function + pr_global_struct->time = (float)sv.time; + pr_global_struct->self = EDICT_TO_PROG(sv_player); + PR_ExecuteProgram (pr_global_struct->ClientConnect); + + if ((Sys_FloatTime() - host_client->netconnection->connecttime) <= sv.time) + Sys_Printf ("%s entered the game\n", host_client->name); + + PR_ExecuteProgram (pr_global_struct->PutClientInServer); + } + +// send all current names, colors, and frag counts + SZ_Clear (&host_client->message); + +// send time of update + MSG_WriteByte (&host_client->message, (int)svc_time); + MSG_WriteFloat (&host_client->message, (float)sv.time); + + for (i=0, client = svs.clients ; imessage, svc_updatename); + MSG_WriteByte (&host_client->message, i); + MSG_WriteString (&host_client->message, client->name); + MSG_WriteByte (&host_client->message, svc_updatefrags); + MSG_WriteByte (&host_client->message, i); + MSG_WriteShort (&host_client->message, client->old_frags); + MSG_WriteByte (&host_client->message, svc_updatecolors); + MSG_WriteByte (&host_client->message, i); + MSG_WriteByte (&host_client->message, client->colors); + } + +// send all current light styles + for (i=0 ; imessage, svc_lightstyle); + MSG_WriteByte (&host_client->message, (char)i); + MSG_WriteString (&host_client->message, sv.lightstyles[i]); + } + +// +// send some stats +// + MSG_WriteByte (&host_client->message, svc_updatestat); + MSG_WriteByte (&host_client->message, STAT_TOTALSECRETS); + MSG_WriteLong (&host_client->message, (int)pr_global_struct->total_secrets); + + MSG_WriteByte (&host_client->message, svc_updatestat); + MSG_WriteByte (&host_client->message, STAT_TOTALMONSTERS); + MSG_WriteLong (&host_client->message, (int)pr_global_struct->total_monsters); + + MSG_WriteByte (&host_client->message, svc_updatestat); + MSG_WriteByte (&host_client->message, STAT_SECRETS); + MSG_WriteLong (&host_client->message, (int)pr_global_struct->found_secrets); + + MSG_WriteByte (&host_client->message, svc_updatestat); + MSG_WriteByte (&host_client->message, STAT_MONSTERS); + MSG_WriteLong (&host_client->message, (int)pr_global_struct->killed_monsters); + + +// +// send a fixangle +// Never send a roll angle, because savegames can catch the server +// in a state where it is expecting the client to correct the angle +// and it won't happen if the game was just loaded, so you wind up +// with a permanent head tilt + ent = EDICT_NUM( 1 + (host_client - svs.clients) ); + MSG_WriteByte (&host_client->message, svc_setangle); + for (i=0 ; i < 2 ; i++) + MSG_WriteAngle (&host_client->message, ent->v.angles[i] ); + MSG_WriteAngle (&host_client->message, 0 ); + + SV_WriteClientdataToMessage (sv_player, &host_client->message); + + MSG_WriteByte (&host_client->message, svc_signonnum); + MSG_WriteByte (&host_client->message, 3); + host_client->sendsignon = true; +} + +#ifdef USEFPM +void Host_Spawn_FPM_f (void) +{ + int i; + client_FPM_t *client; + edict_FPM_t *ent; + + if (cmd_source == src_command) + { + Con_Printf ("spawn is not valid from the console\n"); + return; + } + + if (host_clientFPM->spawned) + { + Con_Printf ("Spawn not valid -- allready spawned\n"); + return; + } + +// run the entrance script + if (svFPM.loadgame) + { // loaded games are fully inited allready + // if this is the last client to be connected, unpause + svFPM.paused = false; + } + else + { + // set up the edict + ent = host_clientFPM->edict; + + Q_memset (&ent->v, 0, progs->entityfields * 4); + ent->v.colormap = (float)NUM_FOR_EDICTFPM(ent); + ent->v.team = (float)((host_clientFPM->colors & 15) + 1); + ent->v.netname = host_clientFPM->name - pr_strings; + + // copy spawn parms out of the client_t + + for (i=0 ; i< NUM_SPAWN_PARMS ; i++) + (&pr_global_struct->parm1)[i] = host_clientFPM->spawn_parms[i]; + + // call the spawn function + + pr_global_struct->time = (float)svFPM.time; + pr_global_struct->self = EDICT_TO_PROGFPM(sv_playerFPM); + PR_ExecuteProgramFPM (pr_global_struct->ClientConnect); + + if ((Sys_FloatTime() - host_clientFPM->netconnection->connecttime) <= svFPM.time) + Sys_Printf ("%s entered the game\n", host_clientFPM->name); + + PR_ExecuteProgramFPM (pr_global_struct->PutClientInServer); + } + + +// send all current names, colors, and frag counts + SZ_Clear (&host_clientFPM->message); + +// send time of update + MSG_WriteByte (&host_clientFPM->message, (int)svc_time); + MSG_WriteFloat (&host_clientFPM->message, (float)svFPM.time); + + for (i=0, client = svsFPM.clients ; imessage, svc_updatename); + MSG_WriteByte (&host_clientFPM->message, i); + MSG_WriteString (&host_clientFPM->message, client->name); + MSG_WriteByte (&host_clientFPM->message, svc_updatefrags); + MSG_WriteByte (&host_clientFPM->message, i); + MSG_WriteShort (&host_clientFPM->message, client->old_frags); + MSG_WriteByte (&host_clientFPM->message, svc_updatecolors); + MSG_WriteByte (&host_clientFPM->message, i); + MSG_WriteByte (&host_clientFPM->message, client->colors); + } + +// send all current light styles + for (i=0 ; imessage, svc_lightstyle); + MSG_WriteByte (&host_clientFPM->message, (char)i); + MSG_WriteString (&host_clientFPM->message, svFPM.lightstyles[i]); + } + +// +// send some stats +// + MSG_WriteByte (&host_clientFPM->message, svc_updatestat); + MSG_WriteByte (&host_clientFPM->message, STAT_TOTALSECRETS); + MSG_WriteLong (&host_clientFPM->message, (int)pr_global_struct->total_secrets); + + MSG_WriteByte (&host_clientFPM->message, svc_updatestat); + MSG_WriteByte (&host_clientFPM->message, STAT_TOTALMONSTERS); + MSG_WriteLong (&host_clientFPM->message, (int)pr_global_struct->total_monsters); + + MSG_WriteByte (&host_clientFPM->message, svc_updatestat); + MSG_WriteByte (&host_clientFPM->message, STAT_SECRETS); + MSG_WriteLong (&host_clientFPM->message, (int)pr_global_struct->found_secrets); + + MSG_WriteByte (&host_clientFPM->message, svc_updatestat); + MSG_WriteByte (&host_clientFPM->message, STAT_MONSTERS); + MSG_WriteLong (&host_clientFPM->message, (int)pr_global_struct->killed_monsters); + + +// +// send a fixangle +// Never send a roll angle, because savegames can catch the server +// in a state where it is expecting the client to correct the angle +// and it won't happen if the game was just loaded, so you wind up +// with a permanent head tilt + ent = EDICT_NUMFPM( 1 + (host_clientFPM - svsFPM.clients) ); + MSG_WriteByte (&host_clientFPM->message, svc_setangle); + for (i=0 ; i < 2 ; i++) + MSG_WriteAngle (&host_clientFPM->message, ent->v.angles[i] ); + MSG_WriteAngle (&host_clientFPM->message, 0 ); + + SV_WriteClientdataToMessageFPM (sv_playerFPM, &host_clientFPM->message); + + MSG_WriteByte (&host_clientFPM->message, svc_signonnum); + MSG_WriteByte (&host_clientFPM->message, 3); + host_client->sendsignon = true; +} +#endif + +/* +================== +Host_Begin_f +================== +*/ +void Host_Begin_f (void) +{ + if (cmd_source == src_command) + { + Con_Printf ("begin is not valid from the console\n"); + return; + } + + host_client->spawned = true; +} + +#ifdef USEFPM +void Host_Begin_FPM_f (void) +{ + if (cmd_source == src_command) + { + Con_Printf ("begin is not valid from the console\n"); + return; + } + + host_clientFPM->spawned = true; +} +#endif +//=========================================================================== + + +/* +================== +Host_Kick_f + +Kicks a user off of the server +================== +*/ +void Host_Kick_f (void) +{ + char *who; + char *message = NULL; + client_t *save; + int i; + qboolean byNumber = false; + + if (cmd_source == src_command) + { + if (!sv.active) + { + Cmd_ForwardToServer (); + return; + } + } + else if (pr_global_struct->deathmatch && !host_client->privileged) + return; + + save = host_client; + + if (Cmd_Argc() > 2 && Q_strcmp(Cmd_Argv(1), "#") == 0) + { + i = (int)(Q_atof(Cmd_Argv(2)) - 1); + if (i < 0 || i >= svs.maxclients) + return; + if (!svs.clients[i].active) + return; + host_client = &svs.clients[i]; + byNumber = true; + } + else + { + for (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++) + { + if (!host_client->active) + continue; + if (Q_strcasecmp(host_client->name, Cmd_Argv(1)) == 0) + break; + } + } + + if (i < svs.maxclients) + { + if (cmd_source == src_command) + if (cls.state == ca_dedicated) + who = "Console"; + else + who = cl_name.string; + else + who = save->name; + + // can't kick yourself! + if (host_client == save) + return; + + if (Cmd_Argc() > 2) + { + message = COM_Parse(Cmd_Args()); + if (byNumber) + { + message++; // skip the # + while (*message == ' ') // skip white space + message++; + message += Q_strlen(Cmd_Argv(2)); // skip the number + } + while (*message && *message == ' ') + message++; + } + if (message) + SV_ClientPrintf ("Kicked by %s: %s\n", who, message); + else + SV_ClientPrintf ("Kicked by %s\n", who); + SV_DropClient (false); + } + + host_client = save; +} + +#ifdef USEFPM +void Host_Kick_FPM_f (void) +{ + char *who; + char *message = NULL; + client_FPM_t *save; + int i; + qboolean byNumber = false; + + if (cmd_source == src_command) + { + if (!svFPM.active) + { + Cmd_ForwardToServer (); + return; + } + } + else if (pr_global_struct->deathmatch && !host_clientFPM->privileged) + return; + + save = host_clientFPM; + + if (Cmd_Argc() > 2 && Q_strcmp(Cmd_Argv(1), "#") == 0) + { + i = (int)(Q_atof(Cmd_Argv(2)) - 1); + if (i < 0 || i >= svsFPM.maxclients) + return; + if (!svsFPM.clients[i].active) + return; + host_clientFPM = &svsFPM.clients[i]; + byNumber = true; + } + else + { + for (i = 0, host_clientFPM = svsFPM.clients; i < svsFPM.maxclients; i++, host_clientFPM++) + { + if (!host_clientFPM->active) + continue; + if (Q_strcasecmp(host_clientFPM->name, Cmd_Argv(1)) == 0) + break; + } + } + + if (i < svsFPM.maxclients) + { + if (cmd_source == src_command) + if (cls.state == ca_dedicated) + who = "Console"; + else + who = cl_name.string; + else + who = save->name; + + // can't kick yourself! + if (host_clientFPM == save) + return; + + if (Cmd_Argc() > 2) + { + message = COM_Parse(Cmd_Args()); + if (byNumber) + { + message++; // skip the # + while (*message == ' ') // skip white space + message++; + message += Q_strlen(Cmd_Argv(2)); // skip the number + } + while (*message && *message == ' ') + message++; + } + if (message) + SV_ClientPrintf ("Kicked by %s: %s\n", who, message); + else + SV_ClientPrintf ("Kicked by %s\n", who); + SV_DropClient (false); + } + + host_clientFPM = save; +} +#endif + +/* +=============================================================================== + +DEBUGGING TOOLS + +=============================================================================== +*/ + +/* +================== +Host_Give_f +================== +*/ +void Host_Give_f (void) +{ + char *t; + int v;//, w; + eval_t *val; + + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_client->privileged) + return; + + t = Cmd_Argv(1); + v = atoi (Cmd_Argv(2)); + + switch (t[0]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + // MED 01/04/97 added hipnotic give stuff + if (r2_mod == 1) + { + if (t[0] == '6') + { + if (t[1] == 'a') + sv_player->v.items = (float)((int)sv_player->v.items | HIT_PROXIMITY_GUN); + else + sv_player->v.items = (float)((int)sv_player->v.items | IT_GRENADE_LAUNCHER); + } + else if (t[0] == '9') + sv_player->v.items = (float)((int)sv_player->v.items | HIT_LASER_CANNON); + else if (t[0] == '0') + sv_player->v.items = (float)((int)sv_player->v.items | HIT_MJOLNIR); + else if (t[0] >= '2') + sv_player->v.items = (float)((int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2'))); + } + else + { + if (t[0] >= '2') + sv_player->v.items = (float)((int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2'))); + } + break; + + case 's': + if (r2_mod == 2) + { + val = GetEdictFieldValue(sv_player, "ammo_shells1"); + if (val) + val->_float = (float)v; + } + + sv_player->v.ammo_shells = (float)v; + break; + case 'n': + if (r2_mod == 2) + { + val = GetEdictFieldValue(sv_player, "ammo_nails1"); + if (val) + { + val->_float = (float)v; + if (sv_player->v.weapon <= IT_LIGHTNING) + sv_player->v.ammo_nails = (float)v; + } + } + else + { + sv_player->v.ammo_nails = (float)v; + } + break; + case 'l': + if (r2_mod == 2) + { + val = GetEdictFieldValue(sv_player, "ammo_lava_nails"); + if (val) + { + val->_float = (float)v; + if (sv_player->v.weapon > IT_LIGHTNING) + sv_player->v.ammo_nails = (float)v; + } + } + break; + case 'r': + if (r2_mod == 2) + { + val = GetEdictFieldValue(sv_player, "ammo_rockets1"); + if (val) + { + val->_float = (float)v; + if (sv_player->v.weapon <= IT_LIGHTNING) + sv_player->v.ammo_rockets = (float)v; + } + } + else + { + sv_player->v.ammo_rockets = (float)v; + } + break; + case 'm': + if (r2_mod == 2) + { + val = GetEdictFieldValue(sv_player, "ammo_multi_rockets"); + if (val) + { + val->_float = (float)v; + if (sv_player->v.weapon > IT_LIGHTNING) + sv_player->v.ammo_rockets = (float)v; + } + } + break; + case 'h': + sv_player->v.health = (float)v; + break; + case 'c': + if (r2_mod == 2) + { + val = GetEdictFieldValue(sv_player, "ammo_cells1"); + if (val) + { + val->_float = (float)v; + if (sv_player->v.weapon <= IT_LIGHTNING) + sv_player->v.ammo_cells = (float)v; + } + } + else + { + sv_player->v.ammo_cells = (float)v; + } + break; + case 'p': + if (r2_mod == 2) + { + val = GetEdictFieldValue(sv_player, "ammo_plasma"); + if (val) + { + val->_float = (float)v; + if (sv_player->v.weapon > IT_LIGHTNING) + sv_player->v.ammo_cells = (float)v; + } + } + break; + } +} + +#ifdef USEFPM +void Host_Give_FPM_f (void) +{ + char *t; + int v;//, w; + eval_t *val; + + if (cmd_source == src_command) + { + Cmd_ForwardToServer (); + return; + } + + if (pr_global_struct->deathmatch && !host_clientFPM->privileged) + return; + + t = Cmd_Argv(1); + v = atoi (Cmd_Argv(2)); + + switch (t[0]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + // MED 01/04/97 added hipnotic give stuff + if (r2_mod == 1) + { + if (t[0] == '6') + { + if (t[1] == 'a') + sv_playerFPM->v.items = (float)((int)sv_playerFPM->v.items | HIT_PROXIMITY_GUN); + else + sv_playerFPM->v.items = (float)((int)sv_playerFPM->v.items | IT_GRENADE_LAUNCHER); + } + else if (t[0] == '9') + sv_playerFPM->v.items = (float)((int)sv_playerFPM->v.items | HIT_LASER_CANNON); + else if (t[0] == '0') + sv_playerFPM->v.items = (float)((int)sv_playerFPM->v.items | HIT_MJOLNIR); + else if (t[0] >= '2') + sv_playerFPM->v.items = (float)((int)sv_playerFPM->v.items | (IT_SHOTGUN << (t[0] - '2'))); + } + else + { + if (t[0] >= '2') + sv_playerFPM->v.items = (float)((int)sv_playerFPM->v.items | (IT_SHOTGUN << (t[0] - '2'))); + } + break; + + case 's': + if (r2_mod == 2) + { + val = GetEdictFieldValueFPM(sv_playerFPM, "ammo_shells1"); + if (val) + val->_float = (float)v; + } + + sv_playerFPM->v.ammo_shells = (float)v; + break; + case 'n': + if (r2_mod == 2) + { + val = GetEdictFieldValueFPM(sv_playerFPM, "ammo_nails1"); + if (val) + { + val->_float = (float)v; + if (sv_playerFPM->v.weapon <= IT_LIGHTNING) + sv_playerFPM->v.ammo_nails = (float)v; + } + } + else + { + sv_playerFPM->v.ammo_nails = (float)v; + } + break; + case 'l': + if (r2_mod == 2) + { + val = GetEdictFieldValueFPM(sv_playerFPM, "ammo_lava_nails"); + if (val) + { + val->_float = (float)v; + if (sv_playerFPM->v.weapon > IT_LIGHTNING) + sv_playerFPM->v.ammo_nails = (float)v; + } + } + break; + case 'r': + if (r2_mod == 2) + { + val = GetEdictFieldValueFPM(sv_playerFPM, "ammo_rockets1"); + if (val) + { + val->_float = (float)v; + if (sv_playerFPM->v.weapon <= IT_LIGHTNING) + sv_playerFPM->v.ammo_rockets = (float)v; + } + } + else + { + sv_playerFPM->v.ammo_rockets = (float)v; + } + break; + case 'm': + if (r2_mod == 2) + { + val = GetEdictFieldValueFPM(sv_playerFPM, "ammo_multi_rockets"); + if (val) + { + val->_float = (float)v; + if (sv_playerFPM->v.weapon > IT_LIGHTNING) + sv_playerFPM->v.ammo_rockets = (float)v; + } + } + break; + case 'h': + sv_playerFPM->v.health = (float)v; + break; + case 'c': + if (r2_mod == 2) + { + val = GetEdictFieldValueFPM(sv_playerFPM, "ammo_cells1"); + if (val) + { + val->_float = (float)v; + if (sv_playerFPM->v.weapon <= IT_LIGHTNING) + sv_playerFPM->v.ammo_cells = (float)v; + } + } + else + { + sv_playerFPM->v.ammo_cells = (float)v; + } + break; + case 'p': + if (r2_mod == 2) + { + val = GetEdictFieldValueFPM(sv_playerFPM, "ammo_plasma"); + if (val) + { + val->_float = (float)v; + if (sv_playerFPM->v.weapon > IT_LIGHTNING) + sv_playerFPM->v.ammo_cells = (float)v; + } + } + break; + } +} +#endif + +edict_t *FindViewthing (void) +{ + int i; + edict_t *e; + + for (i=0 ; iv.classname, "viewthing") ) + return e; + } + Con_Printf ("No viewthing on map\n"); + return NULL; +} + +#ifdef USEFPM +edict_FPM_t *FindViewthingFPM (void) +{ + int i; + edict_FPM_t *e; + + for (i=0 ; iv.classname, "viewthing") ) + return e; + } + Con_Printf ("No viewthing on map\n"); + return NULL; +} +#endif + +/* +================== +Host_Viewmodel_f +================== +*/ +void Host_Viewmodel_f (void) +{ + edict_t *e; + model_t *m; + + e = FindViewthing (); + if (!e) + return; + + m = Mod_ForName (Cmd_Argv(1), false); + if (!m) + { + Con_Printf ("Can't load %s\n", Cmd_Argv(1)); + return; + } + + e->v.frame = 0; + cl.model_precache[(int)e->v.modelindex] = m; +} + +#ifdef USEFPM +void Host_Viewmodel_FPM_f (void) +{ + edict_FPM_t *e; + model_FPM_t *m; + + e = FindViewthingFPM (); + if (!e) + return; + + m = Mod_ForNameFPM (Cmd_Argv(1), false); + if (!m) + { + Con_Printf ("Can't load %s\n", Cmd_Argv(1)); + return; + } + + e->v.frame = 0; + clFPM.model_precache[(int)e->v.modelindex] = m; +} +#endif + +/* +================== +Host_Viewframe_f +================== +*/ +void Host_Viewframe_f (void) +{ + edict_t *e; + int f; + model_t *m; + + e = FindViewthing (); + if (!e) + return; + m = cl.model_precache[(int)e->v.modelindex]; + + f = atoi(Cmd_Argv(1)); + if (f >= m->numframes) + f = m->numframes-1; + + e->v.frame = (float)f; +} + +#ifdef USEFPM +void Host_Viewframe_FPM_f (void) +{ + edict_FPM_t *e; + int f; + model_FPM_t *m; + + e = FindViewthingFPM (); + if (!e) + return; + m = clFPM.model_precache[(int)e->v.modelindex]; + + f = atoi(Cmd_Argv(1)); + if (f >= m->numframes) + f = m->numframes-1; + + e->v.frame = (float)f; +} +#endif + +void PrintFrameName (model_t *m, int frame) +{ + aliashdr_t *hdr; + maliasframedesc_t *pframedesc; + + hdr = (aliashdr_t *)Mod_Extradata (m); + if (!hdr) + return; + pframedesc = &hdr->frames[frame]; + + Con_Printf ("frame %i: %s\n", frame, pframedesc->name); +} + +#ifdef USEFPM +void PrintFrameNameFPM (model_FPM_t *m, int frame) +{ + aliashdr_t *hdr; + maliasframedesc_t *pframedesc; + + hdr = (aliashdr_t *)Mod_ExtradataFPM (m); + if (!hdr) + return; + pframedesc = &hdr->frames[frame]; + + Con_Printf ("frame %i: %s\n", frame, pframedesc->name); +} +#endif + +/* +================== +Host_Viewnext_f +================== +*/ +void Host_Viewnext_f (void) +{ + edict_t *e; + model_t *m; + + e = FindViewthing (); + if (!e) + return; + m = cl.model_precache[(int)e->v.modelindex]; + + e->v.frame = e->v.frame + 1; + if (e->v.frame >= m->numframes) + e->v.frame = (float)(m->numframes - 1); + + PrintFrameName (m, (int)e->v.frame); +} + +#ifdef USEFPM +void Host_Viewnext_FPM_f (void) +{ + edict_FPM_t *e; + model_FPM_t *m; + + e = FindViewthingFPM (); + if (!e) + return; + m = clFPM.model_precache[(int)e->v.modelindex]; + + e->v.frame = e->v.frame + 1; + if (e->v.frame >= m->numframes) + e->v.frame = (float)(m->numframes - 1); + + PrintFrameNameFPM (m, (int)e->v.frame); +} +#endif + +/* +================== +Host_Viewprev_f +================== +*/ +void Host_Viewprev_f (void) +{ + edict_t *e; + model_t *m; + + e = FindViewthing (); + if (!e) + return; + + m = cl.model_precache[(int)e->v.modelindex]; + + e->v.frame = e->v.frame - 1; + if (e->v.frame < 0) + e->v.frame = 0; + + PrintFrameName (m, (int)e->v.frame); +} + +#ifdef USEFPM +void Host_Viewprev_FPM_f (void) +{ + edict_FPM_t *e; + model_FPM_t *m; + + e = FindViewthingFPM (); + if (!e) + return; + + m = clFPM.model_precache[(int)e->v.modelindex]; + + e->v.frame = e->v.frame - 1; + if (e->v.frame < 0) + e->v.frame = 0; + + PrintFrameNameFPM (m, (int)e->v.frame); +} +#endif + +/* +=============================================================================== + +DEMO LOOP CONTROL + +=============================================================================== +*/ + + +/* +================== +Host_Startdemos_f +================== +*/ +void Host_Startdemos_f (void) +{ + int i, c; + + if (cls.state == ca_dedicated) + { + if (!sv.active) + Cbuf_AddText ("map start\n"); + return; + } + + c = Cmd_Argc() - 1; + if (c > MAX_DEMOS) + { + Con_Printf ("Max %i demos in demoloop\n", MAX_DEMOS); + c = MAX_DEMOS; + } + Con_Printf ("%i demo(s) in loop\n", c); + + for (i=1 ; i MAX_DEMOS) + { + Con_Printf ("Max %i demos in demoloop\n", MAX_DEMOS); + c = MAX_DEMOS; + } + Con_Printf ("%i demo(s) in loop\n", c); + + for (i=1 ; i ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Maurus Cuelenaere + * Copyright (C) 2006-2007 by Ingenic Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* + * linux/include/asm-mips/mach-jz4740/jz4740.h + * + * JZ4740 common definition. + * + * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. + * + * Author: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * Include file for Ingenic Semiconductor's JZ4740 CPU. + */ +#ifndef __JZ4740_H__ +#define __JZ4740_H__ + +#ifndef __ASSEMBLY__ + +#define REG8(addr) (*(volatile unsigned char *)(addr)) +#define REG16(addr) (*(volatile unsigned short *)(addr)) +#define REG32(addr) (*(volatile unsigned int *)(addr)) + +#endif /* !ASSEMBLY */ + +/************************************************************************* + * Boot ROM Specification + */ + +/* NOR Boot config */ +#define JZ4740_NORBOOT_8BIT 0x00000000 /* 8-bit data bus flash */ +#define JZ4740_NORBOOT_16BIT 0x10101010 /* 16-bit data bus flash */ +#define JZ4740_NORBOOT_32BIT 0x20202020 /* 32-bit data bus flash */ + +/* NAND Boot config */ +#define JZ4740_NANDBOOT_B8R3 0xffffffff /* 8-bit bus & 3 row cycles */ +#define JZ4740_NANDBOOT_B8R2 0xf0f0f0f0 /* 8-bit bus & 2 row cycles */ +#define JZ4740_NANDBOOT_B16R3 0x0f0f0f0f /* 16-bit bus & 3 row cycles */ +#define JZ4740_NANDBOOT_B16R2 0x00000000 /* 16-bit bus & 2 row cycles */ + + +/************************************************************************* + * Register Definitions + */ +#define CPM_BASE 0xB0000000 +#define INTC_BASE 0xB0001000 +#define TCU_BASE 0xB0002000 +#define WDT_BASE 0xB0002000 +#define RTC_BASE 0xB0003000 +#define GPIO_BASE 0xB0010000 +#define AIC_BASE 0xB0020000 +#define ICDC_BASE 0xB0020000 +#define MSC_BASE 0xB0021000 +#define UART0_BASE 0xB0030000 +#define I2C_BASE 0xB0042000 +#define SSI_BASE 0xB0043000 +#define SADC_BASE 0xB0070000 +#define EMC_BASE 0xB3010000 +#define DMAC_BASE 0xB3020000 +#define UHC_BASE 0xB3030000 +#define UDC_BASE 0xB3040000 +#define LCD_BASE 0xB3050000 +#define SLCD_BASE 0xB3050000 +#define CIM_BASE 0xB3060000 +#define ETH_BASE 0xB3100000 + + +/************************************************************************* + * INTC (Interrupt Controller) + *************************************************************************/ +#define INTC_ISR (INTC_BASE + 0x00) +#define INTC_IMR (INTC_BASE + 0x04) +#define INTC_IMSR (INTC_BASE + 0x08) +#define INTC_IMCR (INTC_BASE + 0x0c) +#define INTC_IPR (INTC_BASE + 0x10) + +#define REG_INTC_ISR REG32(INTC_ISR) +#define REG_INTC_IMR REG32(INTC_IMR) +#define REG_INTC_IMSR REG32(INTC_IMSR) +#define REG_INTC_IMCR REG32(INTC_IMCR) +#define REG_INTC_IPR REG32(INTC_IPR) + +// 1st-level interrupts +#define IRQ_I2C 1 +#define IRQ_EMC 2 +#define IRQ_UHC 3 +#define IRQ_UART0 9 +#define IRQ_SADC 12 +#define IRQ_MSC 14 +#define IRQ_RTC 15 +#define IRQ_SSI 16 +#define IRQ_CIM 17 +#define IRQ_AIC 18 +#define IRQ_ETH 19 +#define IRQ_DMAC 20 +#define IRQ_TCU2 21 +#define IRQ_TCU1 22 +#define IRQ_TCU0 23 +#define IRQ_UDC 24 +#define IRQ_GPIO3 25 +#define IRQ_GPIO2 26 +#define IRQ_GPIO1 27 +#define IRQ_GPIO0 28 +#define IRQ_IPU 29 +#define IRQ_LCD 30 + +// 2nd-level interrupts +#define IRQ_DMA_0 32 /* 32 to 37 for DMAC channel 0 to 5 */ +#define IRQ_GPIO_0 48 /* 48 to 175 for GPIO pin 0 to 127 */ + + +/************************************************************************* + * RTC + *************************************************************************/ +#define RTC_RCR (RTC_BASE + 0x00) /* RTC Control Register */ +#define RTC_RSR (RTC_BASE + 0x04) /* RTC Second Register */ +#define RTC_RSAR (RTC_BASE + 0x08) /* RTC Second Alarm Register */ +#define RTC_RGR (RTC_BASE + 0x0c) /* RTC Regulator Register */ + +#define RTC_HCR (RTC_BASE + 0x20) /* Hibernate Control Register */ +#define RTC_HWFCR (RTC_BASE + 0x24) /* Hibernate Wakeup Filter Counter Reg */ +#define RTC_HRCR (RTC_BASE + 0x28) /* Hibernate Reset Counter Register */ +#define RTC_HWCR (RTC_BASE + 0x2c) /* Hibernate Wakeup Control Register */ +#define RTC_HWRSR (RTC_BASE + 0x30) /* Hibernate Wakeup Status Register */ +#define RTC_HSPR (RTC_BASE + 0x34) /* Hibernate Scratch Pattern Register */ + +#define REG_RTC_RCR REG32(RTC_RCR) +#define REG_RTC_RSR REG32(RTC_RSR) +#define REG_RTC_RSAR REG32(RTC_RSAR) +#define REG_RTC_RGR REG32(RTC_RGR) +#define REG_RTC_HCR REG32(RTC_HCR) +#define REG_RTC_HWFCR REG32(RTC_HWFCR) +#define REG_RTC_HRCR REG32(RTC_HRCR) +#define REG_RTC_HWCR REG32(RTC_HWCR) +#define REG_RTC_HWRSR REG32(RTC_HWRSR) +#define REG_RTC_HSPR REG32(RTC_HSPR) + +/* RTC Control Register */ +#define RTC_RCR_WRDY (1 << 7) /* Write Ready Flag */ +#define RTC_RCR_HZ (1 << 6) /* 1Hz Flag */ +#define RTC_RCR_HZIE (1 << 5) /* 1Hz Interrupt Enable */ +#define RTC_RCR_AF (1 << 4) /* Alarm Flag */ +#define RTC_RCR_AF_BIT 4 /* Alarm Flag */ +#define RTC_RCR_AIE (1 << 3) /* Alarm Interrupt Enable */ +#define RTC_RCR_AE (1 << 2) /* Alarm Enable */ +#define RTC_RCR_RTCE (1 << 0) /* RTC Enable */ + +/* RTC Regulator Register */ +#define RTC_RGR_LOCK (1 << 31) /* Lock Bit */ +#define RTC_RGR_ADJC_BIT 16 +#define RTC_RGR_ADJC_MASK (0x3ff << RTC_RGR_ADJC_BIT) +#define RTC_RGR_NC1HZ_BIT 0 +#define RTC_RGR_NC1HZ_MASK (0xffff << RTC_RGR_NC1HZ_BIT) + +/* Hibernate Control Register */ +#define RTC_HCR_PD (1 << 0) /* Power Down */ + +/* Hibernate Wakeup Filter Counter Register */ +#define RTC_HWFCR_BIT 5 +#define RTC_HWFCR_MASK (0x7ff << RTC_HWFCR_BIT) + +/* Hibernate Reset Counter Register */ +#define RTC_HRCR_BIT 5 +#define RTC_HRCR_MASK (0x7f << RTC_HRCR_BIT) + +/* Hibernate Wakeup Control Register */ +#define RTC_HWCR_EALM (1 << 0) /* RTC alarm wakeup enable */ + +/* Hibernate Wakeup Status Register */ +#define RTC_HWRSR_HR (1 << 5) /* Hibernate reset */ +#define RTC_HWRSR_PPR (1 << 4) /* PPR reset */ +#define RTC_HWRSR_PIN (1 << 1) /* Wakeup pin status bit */ +#define RTC_HWRSR_ALM (1 << 0) /* RTC alarm status bit */ + + +/************************************************************************* + * CPM (Clock reset and Power control Management) + *************************************************************************/ +#define CPM_CPCCR (CPM_BASE+0x00) +#define CPM_CPPCR (CPM_BASE+0x10) +#define CPM_I2SCDR (CPM_BASE+0x60) +#define CPM_LPCDR (CPM_BASE+0x64) +#define CPM_MSCCDR (CPM_BASE+0x68) +#define CPM_UHCCDR (CPM_BASE+0x6C) + +#define CPM_LCR (CPM_BASE+0x04) +#define CPM_CLKGR (CPM_BASE+0x20) +#define CPM_SCR (CPM_BASE+0x24) + +#define CPM_HCR (CPM_BASE+0x30) +#define CPM_HWFCR (CPM_BASE+0x34) +#define CPM_HRCR (CPM_BASE+0x38) +#define CPM_HWCR (CPM_BASE+0x3c) +#define CPM_HWSR (CPM_BASE+0x40) +#define CPM_HSPR (CPM_BASE+0x44) + +#define CPM_RSR (CPM_BASE+0x08) + + +#define REG_CPM_CPCCR REG32(CPM_CPCCR) +#define REG_CPM_CPPCR REG32(CPM_CPPCR) +#define REG_CPM_I2SCDR REG32(CPM_I2SCDR) +#define REG_CPM_LPCDR REG32(CPM_LPCDR) +#define REG_CPM_MSCCDR REG32(CPM_MSCCDR) +#define REG_CPM_UHCCDR REG32(CPM_UHCCDR) + +#define REG_CPM_LCR REG32(CPM_LCR) +#define REG_CPM_CLKGR REG32(CPM_CLKGR) +#define REG_CPM_SCR REG32(CPM_SCR) +#define REG_CPM_HCR REG32(CPM_HCR) +#define REG_CPM_HWFCR REG32(CPM_HWFCR) +#define REG_CPM_HRCR REG32(CPM_HRCR) +#define REG_CPM_HWCR REG32(CPM_HWCR) +#define REG_CPM_HWSR REG32(CPM_HWSR) +#define REG_CPM_HSPR REG32(CPM_HSPR) + +#define REG_CPM_RSR REG32(CPM_RSR) + + +/* Clock Control Register */ +#define CPM_CPCCR_I2CS (1 << 31) +#define CPM_CPCCR_CLKOEN (1 << 30) +#define CPM_CPCCR_UCS (1 << 29) +#define CPM_CPCCR_UDIV_BIT 23 +#define CPM_CPCCR_UDIV_MASK (0x3f << CPM_CPCCR_UDIV_BIT) +#define CPM_CPCCR_CE (1 << 22) +#define CPM_CPCCR_PCS (1 << 21) +#define CPM_CPCCR_LDIV_BIT 16 +#define CPM_CPCCR_LDIV_MASK (0x1f << CPM_CPCCR_LDIV_BIT) +#define CPM_CPCCR_MDIV_BIT 12 +#define CPM_CPCCR_MDIV_MASK (0x0f << CPM_CPCCR_MDIV_BIT) +#define CPM_CPCCR_PDIV_BIT 8 +#define CPM_CPCCR_PDIV_MASK (0x0f << CPM_CPCCR_PDIV_BIT) +#define CPM_CPCCR_HDIV_BIT 4 +#define CPM_CPCCR_HDIV_MASK (0x0f << CPM_CPCCR_HDIV_BIT) +#define CPM_CPCCR_CDIV_BIT 0 +#define CPM_CPCCR_CDIV_MASK (0x0f << CPM_CPCCR_CDIV_BIT) + +/* I2S Clock Divider Register */ +#define CPM_I2SCDR_I2SDIV_BIT 0 +#define CPM_I2SCDR_I2SDIV_MASK (0x1ff << CPM_I2SCDR_I2SDIV_BIT) + +/* LCD Pixel Clock Divider Register */ +#define CPM_LPCDR_PIXDIV_BIT 0 +#define CPM_LPCDR_PIXDIV_MASK (0x1ff << CPM_LPCDR_PIXDIV_BIT) + +/* MSC Clock Divider Register */ +#define CPM_MSCCDR_MSCDIV_BIT 0 +#define CPM_MSCCDR_MSCDIV_MASK (0x1f << CPM_MSCCDR_MSCDIV_BIT) + +/* PLL Control Register */ +#define CPM_CPPCR_PLLM_BIT 23 +#define CPM_CPPCR_PLLM_MASK (0x1ff << CPM_CPPCR_PLLM_BIT) +#define CPM_CPPCR_PLLN_BIT 18 +#define CPM_CPPCR_PLLN_MASK (0x1f << CPM_CPPCR_PLLN_BIT) +#define CPM_CPPCR_PLLOD_BIT 16 +#define CPM_CPPCR_PLLOD_MASK (0x03 << CPM_CPPCR_PLLOD_BIT) +#define CPM_CPPCR_PLLS (1 << 10) +#define CPM_CPPCR_PLLBP (1 << 9) +#define CPM_CPPCR_PLLEN (1 << 8) +#define CPM_CPPCR_PLLST_BIT 0 +#define CPM_CPPCR_PLLST_MASK (0xff << CPM_CPPCR_PLLST_BIT) + +/* Low Power Control Register */ +#define CPM_LCR_DOZE_DUTY_BIT 3 +#define CPM_LCR_DOZE_DUTY_MASK (0x1f << CPM_LCR_DOZE_DUTY_BIT) +#define CPM_LCR_DOZE_ON (1 << 2) +#define CPM_LCR_LPM_BIT 0 +#define CPM_LCR_LPM_MASK (0x3 << CPM_LCR_LPM_BIT) + #define CPM_LCR_LPM_IDLE (0x0 << CPM_LCR_LPM_BIT) + #define CPM_LCR_LPM_SLEEP (0x1 << CPM_LCR_LPM_BIT) + +/* Clock Gate Register */ +#define CPM_CLKGR_UART1 (1 << 15) +#define CPM_CLKGR_UHC (1 << 14) +#define CPM_CLKGR_IPU (1 << 13) +#define CPM_CLKGR_DMAC (1 << 12) +#define CPM_CLKGR_UDC (1 << 11) +#define CPM_CLKGR_LCD (1 << 10) +#define CPM_CLKGR_CIM (1 << 9) +#define CPM_CLKGR_SADC (1 << 8) +#define CPM_CLKGR_MSC (1 << 7) +#define CPM_CLKGR_AIC1 (1 << 6) +#define CPM_CLKGR_AIC2 (1 << 5) +#define CPM_CLKGR_SSI (1 << 4) +#define CPM_CLKGR_I2C (1 << 3) +#define CPM_CLKGR_RTC (1 << 2) +#define CPM_CLKGR_TCU (1 << 1) +#define CPM_CLKGR_UART0 (1 << 0) + +/* Sleep Control Register */ +#define CPM_SCR_O1ST_BIT 8 +#define CPM_SCR_O1ST_MASK (0xff << CPM_SCR_O1ST_BIT) +#define CPM_SCR_USBHOST_SUSPEND (1 << 7) +#define CPM_SCR_USBPHY_ENABLE (1 << 6) +#define CPM_SCR_OSC_ENABLE (1 << 4) + +/* Hibernate Control Register */ +#define CPM_HCR_PD (1 << 0) + +/* Wakeup Filter Counter Register in Hibernate Mode */ +#define CPM_HWFCR_TIME_BIT 0 +#define CPM_HWFCR_TIME_MASK (0x3ff << CPM_HWFCR_TIME_BIT) + +/* Reset Counter Register in Hibernate Mode */ +#define CPM_HRCR_TIME_BIT 0 +#define CPM_HRCR_TIME_MASK (0x7f << CPM_HRCR_TIME_BIT) + +/* Wakeup Control Register in Hibernate Mode */ +#define CPM_HWCR_WLE_LOW (0 << 2) +#define CPM_HWCR_WLE_HIGH (1 << 2) +#define CPM_HWCR_PIN_WAKEUP (1 << 1) +#define CPM_HWCR_RTC_WAKEUP (1 << 0) + +/* Wakeup Status Register in Hibernate Mode */ +#define CPM_HWSR_WSR_PIN (1 << 1) +#define CPM_HWSR_WSR_RTC (1 << 0) + +/* Reset Status Register */ +#define CPM_RSR_HR (1 << 2) +#define CPM_RSR_WR (1 << 1) +#define CPM_RSR_PR (1 << 0) + + +/************************************************************************* + * TCU (Timer Counter Unit) + *************************************************************************/ +#define TCU_TSR (TCU_BASE + 0x1C) /* Timer Stop Register */ +#define TCU_TSSR (TCU_BASE + 0x2C) /* Timer Stop Set Register */ +#define TCU_TSCR (TCU_BASE + 0x3C) /* Timer Stop Clear Register */ +#define TCU_TER (TCU_BASE + 0x10) /* Timer Counter Enable Register */ +#define TCU_TESR (TCU_BASE + 0x14) /* Timer Counter Enable Set Register */ +#define TCU_TECR (TCU_BASE + 0x18) /* Timer Counter Enable Clear Register */ +#define TCU_TFR (TCU_BASE + 0x20) /* Timer Flag Register */ +#define TCU_TFSR (TCU_BASE + 0x24) /* Timer Flag Set Register */ +#define TCU_TFCR (TCU_BASE + 0x28) /* Timer Flag Clear Register */ +#define TCU_TMR (TCU_BASE + 0x30) /* Timer Mask Register */ +#define TCU_TMSR (TCU_BASE + 0x34) /* Timer Mask Set Register */ +#define TCU_TMCR (TCU_BASE + 0x38) /* Timer Mask Clear Register */ +#define TCU_TDFR0 (TCU_BASE + 0x40) /* Timer Data Full Register */ +#define TCU_TDHR0 (TCU_BASE + 0x44) /* Timer Data Half Register */ +#define TCU_TCNT0 (TCU_BASE + 0x48) /* Timer Counter Register */ +#define TCU_TCSR0 (TCU_BASE + 0x4C) /* Timer Control Register */ +#define TCU_TDFR1 (TCU_BASE + 0x50) +#define TCU_TDHR1 (TCU_BASE + 0x54) +#define TCU_TCNT1 (TCU_BASE + 0x58) +#define TCU_TCSR1 (TCU_BASE + 0x5C) +#define TCU_TDFR2 (TCU_BASE + 0x60) +#define TCU_TDHR2 (TCU_BASE + 0x64) +#define TCU_TCNT2 (TCU_BASE + 0x68) +#define TCU_TCSR2 (TCU_BASE + 0x6C) +#define TCU_TDFR3 (TCU_BASE + 0x70) +#define TCU_TDHR3 (TCU_BASE + 0x74) +#define TCU_TCNT3 (TCU_BASE + 0x78) +#define TCU_TCSR3 (TCU_BASE + 0x7C) +#define TCU_TDFR4 (TCU_BASE + 0x80) +#define TCU_TDHR4 (TCU_BASE + 0x84) +#define TCU_TCNT4 (TCU_BASE + 0x88) +#define TCU_TCSR4 (TCU_BASE + 0x8C) +#define TCU_TDFR5 (TCU_BASE + 0x90) +#define TCU_TDHR5 (TCU_BASE + 0x94) +#define TCU_TCNT5 (TCU_BASE + 0x98) +#define TCU_TCSR5 (TCU_BASE + 0x9C) + +#define REG_TCU_TSR REG32(TCU_TSR) +#define REG_TCU_TSSR REG32(TCU_TSSR) +#define REG_TCU_TSCR REG32(TCU_TSCR) +#define REG_TCU_TER REG8(TCU_TER) +#define REG_TCU_TESR REG8(TCU_TESR) +#define REG_TCU_TECR REG8(TCU_TECR) +#define REG_TCU_TFR REG32(TCU_TFR) +#define REG_TCU_TFSR REG32(TCU_TFSR) +#define REG_TCU_TFCR REG32(TCU_TFCR) +#define REG_TCU_TMR REG32(TCU_TMR) +#define REG_TCU_TMSR REG32(TCU_TMSR) +#define REG_TCU_TMCR REG32(TCU_TMCR) +#define REG_TCU_TDFR0 REG16(TCU_TDFR0) +#define REG_TCU_TDHR0 REG16(TCU_TDHR0) +#define REG_TCU_TCNT0 REG16(TCU_TCNT0) +#define REG_TCU_TCSR0 REG16(TCU_TCSR0) +#define REG_TCU_TDFR1 REG16(TCU_TDFR1) +#define REG_TCU_TDHR1 REG16(TCU_TDHR1) +#define REG_TCU_TCNT1 REG16(TCU_TCNT1) +#define REG_TCU_TCSR1 REG16(TCU_TCSR1) +#define REG_TCU_TDFR2 REG16(TCU_TDFR2) +#define REG_TCU_TDHR2 REG16(TCU_TDHR2) +#define REG_TCU_TCNT2 REG16(TCU_TCNT2) +#define REG_TCU_TCSR2 REG16(TCU_TCSR2) +#define REG_TCU_TDFR3 REG16(TCU_TDFR3) +#define REG_TCU_TDHR3 REG16(TCU_TDHR3) +#define REG_TCU_TCNT3 REG16(TCU_TCNT3) +#define REG_TCU_TCSR3 REG16(TCU_TCSR3) +#define REG_TCU_TDFR4 REG16(TCU_TDFR4) +#define REG_TCU_TDHR4 REG16(TCU_TDHR4) +#define REG_TCU_TCNT4 REG16(TCU_TCNT4) +#define REG_TCU_TCSR4 REG16(TCU_TCSR4) + +// n = 0,1,2,3,4,5,6,7 +#define TCU_TDFR(n) (TCU_BASE + (0x40 + (n)*0x10)) /* Timer Data Full Reg */ +#define TCU_TDHR(n) (TCU_BASE + (0x44 + (n)*0x10)) /* Timer Data Half Reg */ +#define TCU_TCNT(n) (TCU_BASE + (0x48 + (n)*0x10)) /* Timer Counter Reg */ +#define TCU_TCSR(n) (TCU_BASE + (0x4C + (n)*0x10)) /* Timer Control Reg */ + +#define REG_TCU_TDFR(n) REG16(TCU_TDFR((n))) +#define REG_TCU_TDHR(n) REG16(TCU_TDHR((n))) +#define REG_TCU_TCNT(n) REG16(TCU_TCNT((n))) +#define REG_TCU_TCSR(n) REG16(TCU_TCSR((n))) + +// Register definitions +#define TCU_TCSR_PWM_SD (1 << 9) +#define TCU_TCSR_PWM_INITL_HIGH (1 << 8) +#define TCU_TCSR_PWM_EN (1 << 7) +#define TCU_TCSR_PRESCALE_BIT 3 +#define TCU_TCSR_PRESCALE_MASK (0x7 << TCU_TCSR_PRESCALE_BIT) + #define TCU_TCSR_PRESCALE1 (0x0 << TCU_TCSR_PRESCALE_BIT) + #define TCU_TCSR_PRESCALE4 (0x1 << TCU_TCSR_PRESCALE_BIT) + #define TCU_TCSR_PRESCALE16 (0x2 << TCU_TCSR_PRESCALE_BIT) + #define TCU_TCSR_PRESCALE64 (0x3 << TCU_TCSR_PRESCALE_BIT) + #define TCU_TCSR_PRESCALE256 (0x4 << TCU_TCSR_PRESCALE_BIT) + #define TCU_TCSR_PRESCALE1024 (0x5 << TCU_TCSR_PRESCALE_BIT) +#define TCU_TCSR_EXT_EN (1 << 2) +#define TCU_TCSR_RTC_EN (1 << 1) +#define TCU_TCSR_PCK_EN (1 << 0) + +#define TCU_TER_TCEN5 (1 << 5) +#define TCU_TER_TCEN4 (1 << 4) +#define TCU_TER_TCEN3 (1 << 3) +#define TCU_TER_TCEN2 (1 << 2) +#define TCU_TER_TCEN1 (1 << 1) +#define TCU_TER_TCEN0 (1 << 0) + +#define TCU_TESR_TCST5 (1 << 5) +#define TCU_TESR_TCST4 (1 << 4) +#define TCU_TESR_TCST3 (1 << 3) +#define TCU_TESR_TCST2 (1 << 2) +#define TCU_TESR_TCST1 (1 << 1) +#define TCU_TESR_TCST0 (1 << 0) + +#define TCU_TECR_TCCL5 (1 << 5) +#define TCU_TECR_TCCL4 (1 << 4) +#define TCU_TECR_TCCL3 (1 << 3) +#define TCU_TECR_TCCL2 (1 << 2) +#define TCU_TECR_TCCL1 (1 << 1) +#define TCU_TECR_TCCL0 (1 << 0) + +#define TCU_TFR_HFLAG5 (1 << 21) +#define TCU_TFR_HFLAG4 (1 << 20) +#define TCU_TFR_HFLAG3 (1 << 19) +#define TCU_TFR_HFLAG2 (1 << 18) +#define TCU_TFR_HFLAG1 (1 << 17) +#define TCU_TFR_HFLAG0 (1 << 16) +#define TCU_TFR_FFLAG5 (1 << 5) +#define TCU_TFR_FFLAG4 (1 << 4) +#define TCU_TFR_FFLAG3 (1 << 3) +#define TCU_TFR_FFLAG2 (1 << 2) +#define TCU_TFR_FFLAG1 (1 << 1) +#define TCU_TFR_FFLAG0 (1 << 0) + +#define TCU_TFSR_HFLAG5 (1 << 21) +#define TCU_TFSR_HFLAG4 (1 << 20) +#define TCU_TFSR_HFLAG3 (1 << 19) +#define TCU_TFSR_HFLAG2 (1 << 18) +#define TCU_TFSR_HFLAG1 (1 << 17) +#define TCU_TFSR_HFLAG0 (1 << 16) +#define TCU_TFSR_FFLAG5 (1 << 5) +#define TCU_TFSR_FFLAG4 (1 << 4) +#define TCU_TFSR_FFLAG3 (1 << 3) +#define TCU_TFSR_FFLAG2 (1 << 2) +#define TCU_TFSR_FFLAG1 (1 << 1) +#define TCU_TFSR_FFLAG0 (1 << 0) + +#define TCU_TFCR_HFLAG5 (1 << 21) +#define TCU_TFCR_HFLAG4 (1 << 20) +#define TCU_TFCR_HFLAG3 (1 << 19) +#define TCU_TFCR_HFLAG2 (1 << 18) +#define TCU_TFCR_HFLAG1 (1 << 17) +#define TCU_TFCR_HFLAG0 (1 << 16) +#define TCU_TFCR_FFLAG5 (1 << 5) +#define TCU_TFCR_FFLAG4 (1 << 4) +#define TCU_TFCR_FFLAG3 (1 << 3) +#define TCU_TFCR_FFLAG2 (1 << 2) +#define TCU_TFCR_FFLAG1 (1 << 1) +#define TCU_TFCR_FFLAG0 (1 << 0) + +#define TCU_TMR_HMASK5 (1 << 21) +#define TCU_TMR_HMASK4 (1 << 20) +#define TCU_TMR_HMASK3 (1 << 19) +#define TCU_TMR_HMASK2 (1 << 18) +#define TCU_TMR_HMASK1 (1 << 17) +#define TCU_TMR_HMASK0 (1 << 16) +#define TCU_TMR_FMASK5 (1 << 5) +#define TCU_TMR_FMASK4 (1 << 4) +#define TCU_TMR_FMASK3 (1 << 3) +#define TCU_TMR_FMASK2 (1 << 2) +#define TCU_TMR_FMASK1 (1 << 1) +#define TCU_TMR_FMASK0 (1 << 0) + +#define TCU_TMSR_HMST5 (1 << 21) +#define TCU_TMSR_HMST4 (1 << 20) +#define TCU_TMSR_HMST3 (1 << 19) +#define TCU_TMSR_HMST2 (1 << 18) +#define TCU_TMSR_HMST1 (1 << 17) +#define TCU_TMSR_HMST0 (1 << 16) +#define TCU_TMSR_FMST5 (1 << 5) +#define TCU_TMSR_FMST4 (1 << 4) +#define TCU_TMSR_FMST3 (1 << 3) +#define TCU_TMSR_FMST2 (1 << 2) +#define TCU_TMSR_FMST1 (1 << 1) +#define TCU_TMSR_FMST0 (1 << 0) + +#define TCU_TMCR_HMCL5 (1 << 21) +#define TCU_TMCR_HMCL4 (1 << 20) +#define TCU_TMCR_HMCL3 (1 << 19) +#define TCU_TMCR_HMCL2 (1 << 18) +#define TCU_TMCR_HMCL1 (1 << 17) +#define TCU_TMCR_HMCL0 (1 << 16) +#define TCU_TMCR_FMCL5 (1 << 5) +#define TCU_TMCR_FMCL4 (1 << 4) +#define TCU_TMCR_FMCL3 (1 << 3) +#define TCU_TMCR_FMCL2 (1 << 2) +#define TCU_TMCR_FMCL1 (1 << 1) +#define TCU_TMCR_FMCL0 (1 << 0) + +#define TCU_TSR_WDTS (1 << 16) +#define TCU_TSR_STOP5 (1 << 5) +#define TCU_TSR_STOP4 (1 << 4) +#define TCU_TSR_STOP3 (1 << 3) +#define TCU_TSR_STOP2 (1 << 2) +#define TCU_TSR_STOP1 (1 << 1) +#define TCU_TSR_STOP0 (1 << 0) + +#define TCU_TSSR_WDTSS (1 << 16) +#define TCU_TSSR_STPS5 (1 << 5) +#define TCU_TSSR_STPS4 (1 << 4) +#define TCU_TSSR_STPS3 (1 << 3) +#define TCU_TSSR_STPS2 (1 << 2) +#define TCU_TSSR_STPS1 (1 << 1) +#define TCU_TSSR_STPS0 (1 << 0) + +#define TCU_TSSR_WDTSC (1 << 16) +#define TCU_TSSR_STPC5 (1 << 5) +#define TCU_TSSR_STPC4 (1 << 4) +#define TCU_TSSR_STPC3 (1 << 3) +#define TCU_TSSR_STPC2 (1 << 2) +#define TCU_TSSR_STPC1 (1 << 1) +#define TCU_TSSR_STPC0 (1 << 0) + + +/************************************************************************* + * WDT (WatchDog Timer) + *************************************************************************/ +#define WDT_TDR (WDT_BASE + 0x00) +#define WDT_TCER (WDT_BASE + 0x04) +#define WDT_TCNT (WDT_BASE + 0x08) +#define WDT_TCSR (WDT_BASE + 0x0C) + +#define REG_WDT_TDR REG16(WDT_TDR) +#define REG_WDT_TCER REG8(WDT_TCER) +#define REG_WDT_TCNT REG16(WDT_TCNT) +#define REG_WDT_TCSR REG16(WDT_TCSR) + +// Register definition +#define WDT_TCSR_PRESCALE_BIT 3 +#define WDT_TCSR_PRESCALE_MASK (0x7 << WDT_TCSR_PRESCALE_BIT) + #define WDT_TCSR_PRESCALE1 (0x0 << WDT_TCSR_PRESCALE_BIT) + #define WDT_TCSR_PRESCALE4 (0x1 << WDT_TCSR_PRESCALE_BIT) + #define WDT_TCSR_PRESCALE16 (0x2 << WDT_TCSR_PRESCALE_BIT) + #define WDT_TCSR_PRESCALE64 (0x3 << WDT_TCSR_PRESCALE_BIT) + #define WDT_TCSR_PRESCALE256 (0x4 << WDT_TCSR_PRESCALE_BIT) + #define WDT_TCSR_PRESCALE1024 (0x5 << WDT_TCSR_PRESCALE_BIT) +#define WDT_TCSR_EXT_EN (1 << 2) +#define WDT_TCSR_RTC_EN (1 << 1) +#define WDT_TCSR_PCK_EN (1 << 0) + +#define WDT_TCER_TCEN (1 << 0) + + +/************************************************************************* + * DMAC (DMA Controller) + *************************************************************************/ + +#define MAX_DMA_NUM 6 /* max 6 channels */ + +#define DMAC_DSAR(n) (DMAC_BASE + (0x00 + (n) * 0x20)) /* DMA source address */ +#define DMAC_DTAR(n) (DMAC_BASE + (0x04 + (n) * 0x20)) /* DMA target address */ +#define DMAC_DTCR(n) (DMAC_BASE + (0x08 + (n) * 0x20)) /* DMA transfer count */ +#define DMAC_DRSR(n) (DMAC_BASE + (0x0c + (n) * 0x20)) /* DMA request source */ +#define DMAC_DCCSR(n) (DMAC_BASE + (0x10 + (n) * 0x20)) /* DMA control/status */ +#define DMAC_DCMD(n) (DMAC_BASE + (0x14 + (n) * 0x20)) /* DMA command */ +#define DMAC_DDA(n) (DMAC_BASE + (0x18 + (n) * 0x20)) /* DMA descriptor address */ +#define DMAC_DMACR (DMAC_BASE + 0x0300) /* DMA control register */ +#define DMAC_DMAIPR (DMAC_BASE + 0x0304) /* DMA interrupt pending */ +#define DMAC_DMADBR (DMAC_BASE + 0x0308) /* DMA doorbell */ +#define DMAC_DMADBSR (DMAC_BASE + 0x030C) /* DMA doorbell set */ + +// channel 0 +#define DMAC_DSAR0 DMAC_DSAR(0) +#define DMAC_DTAR0 DMAC_DTAR(0) +#define DMAC_DTCR0 DMAC_DTCR(0) +#define DMAC_DRSR0 DMAC_DRSR(0) +#define DMAC_DCCSR0 DMAC_DCCSR(0) +#define DMAC_DCMD0 DMAC_DCMD(0) +#define DMAC_DDA0 DMAC_DDA(0) + +// channel 1 +#define DMAC_DSAR1 DMAC_DSAR(1) +#define DMAC_DTAR1 DMAC_DTAR(1) +#define DMAC_DTCR1 DMAC_DTCR(1) +#define DMAC_DRSR1 DMAC_DRSR(1) +#define DMAC_DCCSR1 DMAC_DCCSR(1) +#define DMAC_DCMD1 DMAC_DCMD(1) +#define DMAC_DDA1 DMAC_DDA(1) + +// channel 2 +#define DMAC_DSAR2 DMAC_DSAR(2) +#define DMAC_DTAR2 DMAC_DTAR(2) +#define DMAC_DTCR2 DMAC_DTCR(2) +#define DMAC_DRSR2 DMAC_DRSR(2) +#define DMAC_DCCSR2 DMAC_DCCSR(2) +#define DMAC_DCMD2 DMAC_DCMD(2) +#define DMAC_DDA2 DMAC_DDA(2) + +// channel 3 +#define DMAC_DSAR3 DMAC_DSAR(3) +#define DMAC_DTAR3 DMAC_DTAR(3) +#define DMAC_DTCR3 DMAC_DTCR(3) +#define DMAC_DRSR3 DMAC_DRSR(3) +#define DMAC_DCCSR3 DMAC_DCCSR(3) +#define DMAC_DCMD3 DMAC_DCMD(3) +#define DMAC_DDA3 DMAC_DDA(3) + +// channel 4 +#define DMAC_DSAR4 DMAC_DSAR(4) +#define DMAC_DTAR4 DMAC_DTAR(4) +#define DMAC_DTCR4 DMAC_DTCR(4) +#define DMAC_DRSR4 DMAC_DRSR(4) +#define DMAC_DCCSR4 DMAC_DCCSR(4) +#define DMAC_DCMD4 DMAC_DCMD(4) +#define DMAC_DDA4 DMAC_DDA(4) + +// channel 5 +#define DMAC_DSAR5 DMAC_DSAR(5) +#define DMAC_DTAR5 DMAC_DTAR(5) +#define DMAC_DTCR5 DMAC_DTCR(5) +#define DMAC_DRSR5 DMAC_DRSR(5) +#define DMAC_DCCSR5 DMAC_DCCSR(5) +#define DMAC_DCMD5 DMAC_DCMD(5) +#define DMAC_DDA5 DMAC_DDA(5) + +#define REG_DMAC_DSAR(n) REG32(DMAC_DSAR((n))) +#define REG_DMAC_DTAR(n) REG32(DMAC_DTAR((n))) +#define REG_DMAC_DTCR(n) REG32(DMAC_DTCR((n))) +#define REG_DMAC_DRSR(n) REG32(DMAC_DRSR((n))) +#define REG_DMAC_DCCSR(n) REG32(DMAC_DCCSR((n))) +#define REG_DMAC_DCMD(n) REG32(DMAC_DCMD((n))) +#define REG_DMAC_DDA(n) REG32(DMAC_DDA((n))) +#define REG_DMAC_DMACR REG32(DMAC_DMACR) +#define REG_DMAC_DMAIPR REG32(DMAC_DMAIPR) +#define REG_DMAC_DMADBR REG32(DMAC_DMADBR) +#define REG_DMAC_DMADBSR REG32(DMAC_DMADBSR) + +// DMA request source register +#define DMAC_DRSR_RS_BIT 0 +#define DMAC_DRSR_RS_MASK (0x1f << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_UART0IN (21 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_SSIOUT (22 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_SSIIN (23 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_AICOUT (24 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_AICIN (25 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_MSCOUT (26 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_MSCIN (27 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_TCU (28 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_SADC (29 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_SLCD (30 << DMAC_DRSR_RS_BIT) + +// DMA channel control/status register +#define DMAC_DCCSR_NDES (1 << 31) /* descriptor (0) or not (1) ? */ +#define DMAC_DCCSR_CDOA_BIT 16 /* copy of DMA offset address */ +#define DMAC_DCCSR_CDOA_MASK (0xff << DMAC_DCCSR_CDOA_BIT) +#define DMAC_DCCSR_INV (1 << 6) /* descriptor invalid */ +#define DMAC_DCCSR_AR (1 << 4) /* address error */ +#define DMAC_DCCSR_TT (1 << 3) /* transfer terminated */ +#define DMAC_DCCSR_HLT (1 << 2) /* DMA halted */ +#define DMAC_DCCSR_CT (1 << 1) /* count terminated */ +#define DMAC_DCCSR_EN (1 << 0) /* channel enable bit */ + +// DMA channel command register +#define DMAC_DCMD_SAI (1 << 23) /* source address increment */ +#define DMAC_DCMD_DAI (1 << 22) /* dest address increment */ +#define DMAC_DCMD_RDIL_BIT 16 /* request detection interval length */ +#define DMAC_DCMD_RDIL_MASK (0x0f << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_IGN (0 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_2 (1 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_4 (2 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_8 (3 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_12 (4 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_16 (5 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_20 (6 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_24 (7 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_28 (8 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_32 (9 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_48 (10 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_60 (11 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_64 (12 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_124 (13 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_128 (14 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_200 (15 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_SWDH_BIT 14 /* source port width */ +#define DMAC_DCMD_SWDH_MASK (0x03 << DMAC_DCMD_SWDH_BIT) + #define DMAC_DCMD_SWDH_32 (0 << DMAC_DCMD_SWDH_BIT) + #define DMAC_DCMD_SWDH_8 (1 << DMAC_DCMD_SWDH_BIT) + #define DMAC_DCMD_SWDH_16 (2 << DMAC_DCMD_SWDH_BIT) +#define DMAC_DCMD_DWDH_BIT 12 /* dest port width */ +#define DMAC_DCMD_DWDH_MASK (0x03 << DMAC_DCMD_DWDH_BIT) + #define DMAC_DCMD_DWDH_32 (0 << DMAC_DCMD_DWDH_BIT) + #define DMAC_DCMD_DWDH_8 (1 << DMAC_DCMD_DWDH_BIT) + #define DMAC_DCMD_DWDH_16 (2 << DMAC_DCMD_DWDH_BIT) +#define DMAC_DCMD_DS_BIT 8 /* transfer data size of a data unit */ +#define DMAC_DCMD_DS_MASK (0x07 << DMAC_DCMD_DS_BIT) + #define DMAC_DCMD_DS_32BIT (0 << DMAC_DCMD_DS_BIT) + #define DMAC_DCMD_DS_8BIT (1 << DMAC_DCMD_DS_BIT) + #define DMAC_DCMD_DS_16BIT (2 << DMAC_DCMD_DS_BIT) + #define DMAC_DCMD_DS_16BYTE (3 << DMAC_DCMD_DS_BIT) + #define DMAC_DCMD_DS_32BYTE (4 << DMAC_DCMD_DS_BIT) +#define DMAC_DCMD_TM (1 << 7) /* transfer mode: 0-single 1-block */ +#define DMAC_DCMD_DES_V (1 << 4) /* descriptor valid flag */ +#define DMAC_DCMD_DES_VM (1 << 3) /* descriptor valid mask: 1:support V-bit */ +#define DMAC_DCMD_DES_VIE (1 << 2) /* DMA valid error interrupt enable */ +#define DMAC_DCMD_TIE (1 << 1) /* DMA transfer interrupt enable */ +#define DMAC_DCMD_LINK (1 << 0) /* descriptor link enable */ + +// DMA descriptor address register +#define DMAC_DDA_BASE_BIT 12 /* descriptor base address */ +#define DMAC_DDA_BASE_MASK (0x0fffff << DMAC_DDA_BASE_BIT) +#define DMAC_DDA_OFFSET_BIT 4 /* descriptor offset address */ +#define DMAC_DDA_OFFSET_MASK (0x0ff << DMAC_DDA_OFFSET_BIT) + +// DMA control register +#define DMAC_DMACR_PR_BIT 8 /* channel priority mode */ +#define DMAC_DMACR_PR_MASK (0x03 << DMAC_DMACR_PR_BIT) + #define DMAC_DMACR_PR_012345 (0 << DMAC_DMACR_PR_BIT) + #define DMAC_DMACR_PR_023145 (1 << DMAC_DMACR_PR_BIT) + #define DMAC_DMACR_PR_201345 (2 << DMAC_DMACR_PR_BIT) + #define DMAC_DMACR_PR_RR (3 << DMAC_DMACR_PR_BIT) /* round robin */ +#define DMAC_DMACR_HLT (1 << 3) /* DMA halt flag */ +#define DMAC_DMACR_AR (1 << 2) /* address error flag */ +#define DMAC_DMACR_DMAE (1 << 0) /* DMA enable bit */ + +// DMA doorbell register +#define DMAC_DMADBR_DB5 (1 << 5) /* doorbell for channel 5 */ +#define DMAC_DMADBR_DB4 (1 << 5) /* doorbell for channel 4 */ +#define DMAC_DMADBR_DB3 (1 << 5) /* doorbell for channel 3 */ +#define DMAC_DMADBR_DB2 (1 << 5) /* doorbell for channel 2 */ +#define DMAC_DMADBR_DB1 (1 << 5) /* doorbell for channel 1 */ +#define DMAC_DMADBR_DB0 (1 << 5) /* doorbell for channel 0 */ + +// DMA doorbell set register +#define DMAC_DMADBSR_DBS5 (1 << 5) /* enable doorbell for channel 5 */ +#define DMAC_DMADBSR_DBS4 (1 << 5) /* enable doorbell for channel 4 */ +#define DMAC_DMADBSR_DBS3 (1 << 5) /* enable doorbell for channel 3 */ +#define DMAC_DMADBSR_DBS2 (1 << 5) /* enable doorbell for channel 2 */ +#define DMAC_DMADBSR_DBS1 (1 << 5) /* enable doorbell for channel 1 */ +#define DMAC_DMADBSR_DBS0 (1 << 5) /* enable doorbell for channel 0 */ + +// DMA interrupt pending register +#define DMAC_DMAIPR_CIRQ5 (1 << 5) /* irq pending status for channel 5 */ +#define DMAC_DMAIPR_CIRQ4 (1 << 4) /* irq pending status for channel 4 */ +#define DMAC_DMAIPR_CIRQ3 (1 << 3) /* irq pending status for channel 3 */ +#define DMAC_DMAIPR_CIRQ2 (1 << 2) /* irq pending status for channel 2 */ +#define DMAC_DMAIPR_CIRQ1 (1 << 1) /* irq pending status for channel 1 */ +#define DMAC_DMAIPR_CIRQ0 (1 << 0) /* irq pending status for channel 0 */ + + +/************************************************************************* + * GPIO (General-Purpose I/O Ports) + *************************************************************************/ +#define MAX_GPIO_NUM 128 + +//n = 0,1,2,3 +#define GPIO_PXPIN(n) (GPIO_BASE + (0x00 + (n)*0x100)) /* PIN Level Register */ +#define GPIO_PXDAT(n) (GPIO_BASE + (0x10 + (n)*0x100)) /* Port Data Register */ +#define GPIO_PXDATS(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Data Set Register */ +#define GPIO_PXDATC(n) (GPIO_BASE + (0x18 + (n)*0x100)) /* Port Data Clear Register */ +#define GPIO_PXIM(n) (GPIO_BASE + (0x20 + (n)*0x100)) /* Interrupt Mask Register */ +#define GPIO_PXIMS(n) (GPIO_BASE + (0x24 + (n)*0x100)) /* Interrupt Mask Set Reg */ +#define GPIO_PXIMC(n) (GPIO_BASE + (0x28 + (n)*0x100)) /* Interrupt Mask Clear Reg */ +#define GPIO_PXPE(n) (GPIO_BASE + (0x30 + (n)*0x100)) /* Pull Enable Register */ +#define GPIO_PXPES(n) (GPIO_BASE + (0x34 + (n)*0x100)) /* Pull Enable Set Reg. */ +#define GPIO_PXPEC(n) (GPIO_BASE + (0x38 + (n)*0x100)) /* Pull Enable Clear Reg. */ +#define GPIO_PXFUN(n) (GPIO_BASE + (0x40 + (n)*0x100)) /* Function Register */ +#define GPIO_PXFUNS(n) (GPIO_BASE + (0x44 + (n)*0x100)) /* Function Set Register */ +#define GPIO_PXFUNC(n) (GPIO_BASE + (0x48 + (n)*0x100)) /* Function Clear Register */ +#define GPIO_PXSEL(n) (GPIO_BASE + (0x50 + (n)*0x100)) /* Select Register */ +#define GPIO_PXSELS(n) (GPIO_BASE + (0x54 + (n)*0x100)) /* Select Set Register */ +#define GPIO_PXSELC(n) (GPIO_BASE + (0x58 + (n)*0x100)) /* Select Clear Register */ +#define GPIO_PXDIR(n) (GPIO_BASE + (0x60 + (n)*0x100)) /* Direction Register */ +#define GPIO_PXDIRS(n) (GPIO_BASE + (0x64 + (n)*0x100)) /* Direction Set Register */ +#define GPIO_PXDIRC(n) (GPIO_BASE + (0x68 + (n)*0x100)) /* Direction Clear Register */ +#define GPIO_PXTRG(n) (GPIO_BASE + (0x70 + (n)*0x100)) /* Trigger Register */ +#define GPIO_PXTRGS(n) (GPIO_BASE + (0x74 + (n)*0x100)) /* Trigger Set Register */ +#define GPIO_PXTRGC(n) (GPIO_BASE + (0x78 + (n)*0x100)) /* Trigger Set Register */ +#define GPIO_PXFLG(n) (GPIO_BASE + (0x80 + (n)*0x100)) /* Port Flag Register */ +#define GPIO_PXFLGC(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Flag clear Register */ + +#define REG_GPIO_PXPIN(n) REG32(GPIO_PXPIN((n))) /* PIN level */ +#define REG_GPIO_PXDAT(n) REG32(GPIO_PXDAT((n))) /* 1: interrupt pending */ +#define REG_GPIO_PXDATS(n) REG32(GPIO_PXDATS((n))) +#define REG_GPIO_PXDATC(n) REG32(GPIO_PXDATC((n))) +#define REG_GPIO_PXIM(n) REG32(GPIO_PXIM((n))) /* 1: mask pin interrupt */ +#define REG_GPIO_PXIMS(n) REG32(GPIO_PXIMS((n))) +#define REG_GPIO_PXIMC(n) REG32(GPIO_PXIMC((n))) +#define REG_GPIO_PXPE(n) REG32(GPIO_PXPE((n))) /* 1: disable pull up/down */ +#define REG_GPIO_PXPES(n) REG32(GPIO_PXPES((n))) +#define REG_GPIO_PXPEC(n) REG32(GPIO_PXPEC((n))) +#define REG_GPIO_PXFUN(n) REG32(GPIO_PXFUN((n))) /* 0:GPIO or intr, 1:FUNC */ +#define REG_GPIO_PXFUNS(n) REG32(GPIO_PXFUNS((n))) +#define REG_GPIO_PXFUNC(n) REG32(GPIO_PXFUNC((n))) +#define REG_GPIO_PXSEL(n) REG32(GPIO_PXSEL((n))) /* 0:GPIO/Fun0,1:intr/fun1*/ +#define REG_GPIO_PXSELS(n) REG32(GPIO_PXSELS((n))) +#define REG_GPIO_PXSELC(n) REG32(GPIO_PXSELC((n))) +#define REG_GPIO_PXDIR(n) REG32(GPIO_PXDIR((n))) /* 0:input/low-level-trig/falling-edge-trig, 1:output/high-level-trig/rising-edge-trig */ +#define REG_GPIO_PXDIRS(n) REG32(GPIO_PXDIRS((n))) +#define REG_GPIO_PXDIRC(n) REG32(GPIO_PXDIRC((n))) +#define REG_GPIO_PXTRG(n) REG32(GPIO_PXTRG((n))) /* 0:level-trigger, 1:edge-trigger */ +#define REG_GPIO_PXTRGS(n) REG32(GPIO_PXTRGS((n))) +#define REG_GPIO_PXTRGC(n) REG32(GPIO_PXTRGC((n))) +#define REG_GPIO_PXFLG(n) REG32(GPIO_PXFLG((n))) /* interrupt flag */ +#define REG_GPIO_PXFLGC(n) REG32(GPIO_PXFLGC((n))) /* interrupt flag */ + + +/************************************************************************* + * UART + *************************************************************************/ + +#define IRDA_BASE UART0_BASE +#define UART_BASE UART0_BASE +#define UART_OFF 0x1000 + +/* Register Offset */ +#define OFF_RDR (0x00) /* R 8b H'xx */ +#define OFF_TDR (0x00) /* W 8b H'xx */ +#define OFF_DLLR (0x00) /* RW 8b H'00 */ +#define OFF_DLHR (0x04) /* RW 8b H'00 */ +#define OFF_IER (0x04) /* RW 8b H'00 */ +#define OFF_ISR (0x08) /* R 8b H'01 */ +#define OFF_FCR (0x08) /* W 8b H'00 */ +#define OFF_LCR (0x0C) /* RW 8b H'00 */ +#define OFF_MCR (0x10) /* RW 8b H'00 */ +#define OFF_LSR (0x14) /* R 8b H'00 */ +#define OFF_MSR (0x18) /* R 8b H'00 */ +#define OFF_SPR (0x1C) /* RW 8b H'00 */ +#define OFF_SIRCR (0x20) /* RW 8b H'00, UART0 */ +#define OFF_UMR (0x24) /* RW 8b H'00, UART M Register */ +#define OFF_UACR (0x28) /* RW 8b H'00, UART Add Cycle Register */ + +/* Register Address */ +#define UART0_RDR (UART0_BASE + OFF_RDR) +#define UART0_TDR (UART0_BASE + OFF_TDR) +#define UART0_DLLR (UART0_BASE + OFF_DLLR) +#define UART0_DLHR (UART0_BASE + OFF_DLHR) +#define UART0_IER (UART0_BASE + OFF_IER) +#define UART0_ISR (UART0_BASE + OFF_ISR) +#define UART0_FCR (UART0_BASE + OFF_FCR) +#define UART0_LCR (UART0_BASE + OFF_LCR) +#define UART0_MCR (UART0_BASE + OFF_MCR) +#define UART0_LSR (UART0_BASE + OFF_LSR) +#define UART0_MSR (UART0_BASE + OFF_MSR) +#define UART0_SPR (UART0_BASE + OFF_SPR) +#define UART0_SIRCR (UART0_BASE + OFF_SIRCR) +#define UART0_UMR (UART0_BASE + OFF_UMR) +#define UART0_UACR (UART0_BASE + OFF_UACR) + +/* + * Define macros for UART_IER + * UART Interrupt Enable Register + */ +#define UART_IER_RIE (1 << 0) /* 0: receive fifo "full" interrupt disable */ +#define UART_IER_TIE (1 << 1) /* 0: transmit fifo "empty" interrupt disable */ +#define UART_IER_RLIE (1 << 2) /* 0: receive line status interrupt disable */ +#define UART_IER_MIE (1 << 3) /* 0: modem status interrupt disable */ +#define UART_IER_RTIE (1 << 4) /* 0: receive timeout interrupt disable */ + +/* + * Define macros for UART_ISR + * UART Interrupt Status Register + */ +#define UART_ISR_IP (1 << 0) /* 0: interrupt is pending 1: no interrupt */ +#define UART_ISR_IID (7 << 1) /* Source of Interrupt */ +#define UART_ISR_IID_MSI (0 << 1) /* Modem status interrupt */ +#define UART_ISR_IID_THRI (1 << 1) /* Transmitter holding register empty */ +#define UART_ISR_IID_RDI (2 << 1) /* Receiver data interrupt */ +#define UART_ISR_IID_RLSI (3 << 1) /* Receiver line status interrupt */ +#define UART_ISR_FFMS (3 << 6) /* FIFO mode select, set when UART_FCR.FE is set to 1 */ +#define UART_ISR_FFMS_NO_FIFO (0 << 6) +#define UART_ISR_FFMS_FIFO_MODE (3 << 6) + +/* + * Define macros for UART_FCR + * UART FIFO Control Register + */ +#define UART_FCR_FE (1 << 0) /* 0: non-FIFO mode 1: FIFO mode */ +#define UART_FCR_RFLS (1 << 1) /* write 1 to flush receive FIFO */ +#define UART_FCR_TFLS (1 << 2) /* write 1 to flush transmit FIFO */ +#define UART_FCR_DMS (1 << 3) /* 0: disable DMA mode */ +#define UART_FCR_UUE (1 << 4) /* 0: disable UART */ +#define UART_FCR_RTRG (3 << 6) /* Receive FIFO Data Trigger */ +#define UART_FCR_RTRG_1 (0 << 6) +#define UART_FCR_RTRG_4 (1 << 6) +#define UART_FCR_RTRG_8 (2 << 6) +#define UART_FCR_RTRG_15 (3 << 6) + +/* + * Define macros for UART_LCR + * UART Line Control Register + */ +#define UART_LCR_WLEN (3 << 0) /* word length */ +#define UART_LCR_WLEN_5 (0 << 0) +#define UART_LCR_WLEN_6 (1 << 0) +#define UART_LCR_WLEN_7 (2 << 0) +#define UART_LCR_WLEN_8 (3 << 0) +#define UART_LCR_STOP (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8 + 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */ +#define UART_LCR_STOP_1 (0 << 2) /* 0: 1 stop bit when word length is 5,6,7,8 + 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */ +#define UART_LCR_STOP_2 (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8 + 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */ + +#define UART_LCR_PE (1 << 3) /* 0: parity disable */ +#define UART_LCR_PROE (1 << 4) /* 0: even parity 1: odd parity */ +#define UART_LCR_SPAR (1 << 5) /* 0: sticky parity disable */ +#define UART_LCR_SBRK (1 << 6) /* write 0 normal, write 1 send break */ +#define UART_LCR_DLAB (1 << 7) /* 0: access UART_RDR/TDR/IER 1: access UART_DLLR/DLHR */ + +/* + * Define macros for UART_LSR + * UART Line Status Register + */ +#define UART_LSR_DR (1 << 0) /* 0: receive FIFO is empty 1: receive data is ready */ +#define UART_LSR_ORER (1 << 1) /* 0: no overrun error */ +#define UART_LSR_PER (1 << 2) /* 0: no parity error */ +#define UART_LSR_FER (1 << 3) /* 0; no framing error */ +#define UART_LSR_BRK (1 << 4) /* 0: no break detected 1: receive a break signal */ +#define UART_LSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */ +#define UART_LSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */ +#define UART_LSR_RFER (1 << 7) /* 0: no receive error 1: receive error in FIFO mode */ + +/* + * Define macros for UART_MCR + * UART Modem Control Register + */ +#define UART_MCR_DTR (1 << 0) /* 0: DTR_ ouput high */ +#define UART_MCR_RTS (1 << 1) /* 0: RTS_ output high */ +#define UART_MCR_OUT1 (1 << 2) /* 0: UART_MSR.RI is set to 0 and RI_ input high */ +#define UART_MCR_OUT2 (1 << 3) /* 0: UART_MSR.DCD is set to 0 and DCD_ input high */ +#define UART_MCR_LOOP (1 << 4) /* 0: normal 1: loopback mode */ +#define UART_MCR_MCE (1 << 7) /* 0: modem function is disable */ + +/* + * Define macros for UART_MSR + * UART Modem Status Register + */ +#define UART_MSR_DCTS (1 << 0) /* 0: no change on CTS_ pin since last read of UART_MSR */ +#define UART_MSR_DDSR (1 << 1) /* 0: no change on DSR_ pin since last read of UART_MSR */ +#define UART_MSR_DRI (1 << 2) /* 0: no change on RI_ pin since last read of UART_MSR */ +#define UART_MSR_DDCD (1 << 3) /* 0: no change on DCD_ pin since last read of UART_MSR */ +#define UART_MSR_CTS (1 << 4) /* 0: CTS_ pin is high */ +#define UART_MSR_DSR (1 << 5) /* 0: DSR_ pin is high */ +#define UART_MSR_RI (1 << 6) /* 0: RI_ pin is high */ +#define UART_MSR_DCD (1 << 7) /* 0: DCD_ pin is high */ + +/* + * Define macros for SIRCR + * Slow IrDA Control Register + */ +#define SIRCR_TSIRE (1 << 0) /* 0: transmitter is in UART mode 1: IrDA mode */ +#define SIRCR_RSIRE (1 << 1) /* 0: receiver is in UART mode 1: IrDA mode */ +#define SIRCR_TPWS (1 << 2) /* 0: transmit 0 pulse width is 3/16 of bit length + 1: 0 pulse width is 1.6us for 115.2Kbps */ +#define SIRCR_TXPL (1 << 3) /* 0: encoder generates a positive pulse for 0 */ +#define SIRCR_RXPL (1 << 4) /* 0: decoder interprets positive pulse as 0 */ + + +/************************************************************************* + * AIC (AC97/I2S Controller) + *************************************************************************/ +#define AIC_FR (AIC_BASE + 0x000) +#define AIC_CR (AIC_BASE + 0x004) +#define AIC_ACCR1 (AIC_BASE + 0x008) +#define AIC_ACCR2 (AIC_BASE + 0x00C) +#define AIC_I2SCR (AIC_BASE + 0x010) +#define AIC_SR (AIC_BASE + 0x014) +#define AIC_ACSR (AIC_BASE + 0x018) +#define AIC_I2SSR (AIC_BASE + 0x01C) +#define AIC_ACCAR (AIC_BASE + 0x020) +#define AIC_ACCDR (AIC_BASE + 0x024) +#define AIC_ACSAR (AIC_BASE + 0x028) +#define AIC_ACSDR (AIC_BASE + 0x02C) +#define AIC_I2SDIV (AIC_BASE + 0x030) +#define AIC_DR (AIC_BASE + 0x034) + +#define REG_AIC_FR REG32(AIC_FR) +#define REG_AIC_CR REG32(AIC_CR) +#define REG_AIC_ACCR1 REG32(AIC_ACCR1) +#define REG_AIC_ACCR2 REG32(AIC_ACCR2) +#define REG_AIC_I2SCR REG32(AIC_I2SCR) +#define REG_AIC_SR REG32(AIC_SR) +#define REG_AIC_ACSR REG32(AIC_ACSR) +#define REG_AIC_I2SSR REG32(AIC_I2SSR) +#define REG_AIC_ACCAR REG32(AIC_ACCAR) +#define REG_AIC_ACCDR REG32(AIC_ACCDR) +#define REG_AIC_ACSAR REG32(AIC_ACSAR) +#define REG_AIC_ACSDR REG32(AIC_ACSDR) +#define REG_AIC_I2SDIV REG32(AIC_I2SDIV) +#define REG_AIC_DR REG32(AIC_DR) + +/* AIC Controller Configuration Register (AIC_FR) */ + +#define AIC_FR_RFTH_BIT 12 /* Receive FIFO Threshold */ +#define AIC_FR_RFTH_MASK (0xf << AIC_FR_RFTH_BIT) +#define AIC_FR_TFTH_BIT 8 /* Transmit FIFO Threshold */ +#define AIC_FR_TFTH_MASK (0xf << AIC_FR_TFTH_BIT) +#define AIC_FR_ICDC (1 << 5) /* External(0) or Internal CODEC(1) */ +#define AIC_FR_AUSEL (1 << 4) /* AC97(0) or I2S/MSB-justified(1) */ +#define AIC_FR_RST (1 << 3) /* AIC registers reset */ +#define AIC_FR_BCKD (1 << 2) /* I2S BIT_CLK direction, 0:input,1:output */ +#define AIC_FR_SYNCD (1 << 1) /* I2S SYNC direction, 0:input,1:output */ +#define AIC_FR_ENB (1 << 0) /* AIC enable bit */ + +/* AIC Controller Common Control Register (AIC_CR) */ + +#define AIC_CR_OSS_BIT 19 /* Output Sample Size from memory (AIC V2 only) */ +#define AIC_CR_OSS_MASK (0x7 << AIC_CR_OSS_BIT) + #define AIC_CR_OSS_8BIT (0x0 << AIC_CR_OSS_BIT) + #define AIC_CR_OSS_16BIT (0x1 << AIC_CR_OSS_BIT) + #define AIC_CR_OSS_18BIT (0x2 << AIC_CR_OSS_BIT) + #define AIC_CR_OSS_20BIT (0x3 << AIC_CR_OSS_BIT) + #define AIC_CR_OSS_24BIT (0x4 << AIC_CR_OSS_BIT) +#define AIC_CR_ISS_BIT 16 /* Input Sample Size from memory (AIC V2 only) */ +#define AIC_CR_ISS_MASK (0x7 << AIC_CR_ISS_BIT) + #define AIC_CR_ISS_8BIT (0x0 << AIC_CR_ISS_BIT) + #define AIC_CR_ISS_16BIT (0x1 << AIC_CR_ISS_BIT) + #define AIC_CR_ISS_18BIT (0x2 << AIC_CR_ISS_BIT) + #define AIC_CR_ISS_20BIT (0x3 << AIC_CR_ISS_BIT) + #define AIC_CR_ISS_24BIT (0x4 << AIC_CR_ISS_BIT) +#define AIC_CR_RDMS (1 << 15) /* Receive DMA enable */ +#define AIC_CR_TDMS (1 << 14) /* Transmit DMA enable */ +#define AIC_CR_M2S (1 << 11) /* Mono to Stereo enable */ +#define AIC_CR_ENDSW (1 << 10) /* Endian switch enable */ +#define AIC_CR_AVSTSU (1 << 9) /* Signed <-> Unsigned toggle enable */ +#define AIC_CR_FLUSH (1 << 8) /* Flush FIFO */ +#define AIC_CR_EROR (1 << 6) /* Enable ROR interrupt */ +#define AIC_CR_ETUR (1 << 5) /* Enable TUR interrupt */ +#define AIC_CR_ERFS (1 << 4) /* Enable RFS interrupt */ +#define AIC_CR_ETFS (1 << 3) /* Enable TFS interrupt */ +#define AIC_CR_ENLBF (1 << 2) /* Enable Loopback Function */ +#define AIC_CR_ERPL (1 << 1) /* Enable Playback Function */ +#define AIC_CR_EREC (1 << 0) /* Enable Record Function */ + +/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */ + +#define AIC_ACCR1_RS_BIT 16 /* Receive Valid Slots */ +#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT) + #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */ + #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */ + #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */ + #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit, LFE */ + #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit, Surround Right */ + #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit, Surround Left */ + #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit, PCM Center */ + #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */ + #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit, PCM Right */ + #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit, PCM Left */ +#define AIC_ACCR1_XS_BIT 0 /* Transmit Valid Slots */ +#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT) + #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */ + #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */ + #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */ + #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit, LFE */ + #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit, Surround Right */ + #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit, Surround Left */ + #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit, PCM Center */ + #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */ + #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit, PCM Right */ + #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit, PCM Left */ + +/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */ + +#define AIC_ACCR2_ERSTO (1 << 18) /* Enable RSTO interrupt */ +#define AIC_ACCR2_ESADR (1 << 17) /* Enable SADR interrupt */ +#define AIC_ACCR2_ECADT (1 << 16) /* Enable CADT interrupt */ +#define AIC_ACCR2_OASS_BIT 8 /* Output Sample Size for AC-link */ +#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT) + #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */ + #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */ + #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */ + #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */ +#define AIC_ACCR2_IASS_BIT 6 /* Output Sample Size for AC-link */ +#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT) + #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */ + #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */ + #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */ + #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */ +#define AIC_ACCR2_SO (1 << 3) /* SDATA_OUT output value */ +#define AIC_ACCR2_SR (1 << 2) /* RESET# pin level */ +#define AIC_ACCR2_SS (1 << 1) /* SYNC pin level */ +#define AIC_ACCR2_SA (1 << 0) /* SYNC and SDATA_OUT alternation */ + +/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */ + +#define AIC_I2SCR_STPBK (1 << 12) /* Stop BIT_CLK for I2S/MSB-justified */ +#define AIC_I2SCR_WL_BIT 1 /* Input/Output Sample Size for I2S/MSB-justified */ +#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT) + #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */ + #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */ + #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */ + #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */ + #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */ +#define AIC_I2SCR_AMSL (1 << 0) /* 0:I2S, 1:MSB-justified */ + +/* AIC Controller FIFO Status Register (AIC_SR) */ + +#define AIC_SR_RFL_BIT 24 /* Receive FIFO Level */ +#define AIC_SR_RFL_MASK (0x3f << AIC_SR_RFL_BIT) +#define AIC_SR_TFL_BIT 8 /* Transmit FIFO level */ +#define AIC_SR_TFL_MASK (0x3f << AIC_SR_TFL_BIT) +#define AIC_SR_ROR (1 << 6) /* Receive FIFO Overrun */ +#define AIC_SR_TUR (1 << 5) /* Transmit FIFO Underrun */ +#define AIC_SR_RFS (1 << 4) /* Receive FIFO Service Request */ +#define AIC_SR_TFS (1 << 3) /* Transmit FIFO Service Request */ + +/* AIC Controller AC-link Status Register (AIC_ACSR) */ + +#define AIC_ACSR_SLTERR (1 << 21) /* Slot Error Flag */ +#define AIC_ACSR_CRDY (1 << 20) /* External CODEC Ready Flag */ +#define AIC_ACSR_CLPM (1 << 19) /* External CODEC low power mode flag */ +#define AIC_ACSR_RSTO (1 << 18) /* External CODEC regs read status timeout */ +#define AIC_ACSR_SADR (1 << 17) /* External CODEC regs status addr and data received */ +#define AIC_ACSR_CADT (1 << 16) /* Command Address and Data Transmitted */ + +/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */ + +#define AIC_I2SSR_BSY (1 << 2) /* AIC Busy in I2S/MSB-justified format */ + +/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */ + +#define AIC_ACCAR_CAR_BIT 0 +#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT) + +/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */ + +#define AIC_ACCDR_CDR_BIT 0 +#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT) + +/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */ + +#define AIC_ACSAR_SAR_BIT 0 +#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT) + +/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */ + +#define AIC_ACSDR_SDR_BIT 0 +#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT) + +/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */ + +#define AIC_I2SDIV_DIV_BIT 0 +#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT) + #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */ + #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */ + #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */ + #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */ + #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */ + #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */ + + +/************************************************************************* + * ICDC (Internal CODEC) + *************************************************************************/ +#define ICDC_CR (ICDC_BASE + 0x0400) /* ICDC Control Register */ +#define ICDC_APWAIT (ICDC_BASE + 0x0404) /* Anti-Pop WAIT Stage Timing Control Register */ +#define ICDC_APPRE (ICDC_BASE + 0x0408) /* Anti-Pop HPEN-PRE Stage Timing Control Register */ +#define ICDC_APHPEN (ICDC_BASE + 0x040C) /* Anti-Pop HPEN Stage Timing Control Register */ +#define ICDC_APSR (ICDC_BASE + 0x0410) /* Anti-Pop Status Register */ +#define ICDC_CDCCR1 (ICDC_BASE + 0x0080) +#define ICDC_CDCCR2 (ICDC_BASE + 0x0084) + +#define REG_ICDC_CR REG32(ICDC_CR) +#define REG_ICDC_APWAIT REG32(ICDC_APWAIT) +#define REG_ICDC_APPRE REG32(ICDC_APPRE) +#define REG_ICDC_APHPEN REG32(ICDC_APHPEN) +#define REG_ICDC_APSR REG32(ICDC_APSR) +#define REG_ICDC_CDCCR1 REG32(ICDC_CDCCR1) +#define REG_ICDC_CDCCR2 REG32(ICDC_CDCCR2) + +/* ICDC Control Register */ +#define ICDC_CR_LINVOL_BIT 24 /* LINE Input Volume Gain: GAIN=LINVOL*1.5-34.5 */ +#define ICDC_CR_LINVOL_MASK (0x1f << ICDC_CR_LINVOL_BIT) +#define ICDC_CR_ASRATE_BIT 20 /* Audio Sample Rate */ +#define ICDC_CR_ASRATE_MASK (0x0f << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_8000 (0x0 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_11025 (0x1 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_12000 (0x2 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_16000 (0x3 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_22050 (0x4 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_24000 (0x5 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_32000 (0x6 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_44100 (0x7 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_48000 (0x8 << ICDC_CR_ASRATE_BIT) +#define ICDC_CR_MICBG_BIT 18 /* MIC Boost Gain */ +#define ICDC_CR_MICBG_MASK (0x3 << ICDC_CR_MICBG_BIT) + #define ICDC_CR_MICBG_0DB (0x0 << ICDC_CR_MICBG_BIT) + #define ICDC_CR_MICBG_6DB (0x1 << ICDC_CR_MICBG_BIT) + #define ICDC_CR_MICBG_12DB (0x2 << ICDC_CR_MICBG_BIT) + #define ICDC_CR_MICBG_20DB (0x3 << ICDC_CR_MICBG_BIT) +#define ICDC_CR_HPVOL_BIT 16 /* Headphone Volume Gain */ +#define ICDC_CR_HPVOL_MASK (0x3 << ICDC_CR_HPVOL_BIT) + #define ICDC_CR_HPVOL_0DB (0x0 << ICDC_CR_HPVOL_BIT) + #define ICDC_CR_HPVOL_2DB (0x1 << ICDC_CR_HPVOL_BIT) + #define ICDC_CR_HPVOL_4DB (0x2 << ICDC_CR_HPVOL_BIT) + #define ICDC_CR_HPVOL_6DB (0x3 << ICDC_CR_HPVOL_BIT) +#define ICDC_CR_ELINEIN (1 << 13) /* Enable LINE Input */ +#define ICDC_CR_EMIC (1 << 12) /* Enable MIC Input */ +#define ICDC_CR_SW1ON (1 << 11) /* Switch 1 in CODEC is on */ +#define ICDC_CR_EADC (1 << 10) /* Enable ADC */ +#define ICDC_CR_SW2ON (1 << 9) /* Switch 2 in CODEC is on */ +#define ICDC_CR_EDAC (1 << 8) /* Enable DAC */ +#define ICDC_CR_HPMUTE (1 << 5) /* Headphone Mute */ +#define ICDC_CR_HPTON (1 << 4) /* Headphone Amplifier Trun On */ +#define ICDC_CR_HPTOFF (1 << 3) /* Headphone Amplifier Trun Off */ +#define ICDC_CR_TAAP (1 << 2) /* Turn Around of the Anti-Pop Procedure */ +#define ICDC_CR_EAP (1 << 1) /* Enable Anti-Pop Procedure */ +#define ICDC_CR_SUSPD (1 << 0) /* CODEC Suspend */ + +/* Anti-Pop WAIT Stage Timing Control Register */ +#define ICDC_APWAIT_WAITSN_BIT 0 +#define ICDC_APWAIT_WAITSN_MASK (0x7ff << ICDC_APWAIT_WAITSN_BIT) + +/* Anti-Pop HPEN-PRE Stage Timing Control Register */ +#define ICDC_APPRE_PRESN_BIT 0 +#define ICDC_APPRE_PRESN_MASK (0x1ff << ICDC_APPRE_PRESN_BIT) + +/* Anti-Pop HPEN Stage Timing Control Register */ +#define ICDC_APHPEN_HPENSN_BIT 0 +#define ICDC_APHPEN_HPENSN_MASK (0x3fff << ICDC_APHPEN_HPENSN_BIT) + +/* Anti-Pop Status Register */ +#define ICDC_SR_HPST_BIT 14 /* Headphone Amplifier State */ +#define ICDC_SR_HPST_MASK (0x7 << ICDC_SR_HPST_BIT) +#define ICDC_SR_HPST_HP_OFF (0x0 << ICDC_SR_HPST_BIT) /* HP amplifier is off */ +#define ICDC_SR_HPST_TON_WAIT (0x1 << ICDC_SR_HPST_BIT) /* wait state in turn-on */ + #define ICDC_SR_HPST_TON_PRE (0x2 << ICDC_SR_HPST_BIT) /* pre-enable state in turn-on */ +#define ICDC_SR_HPST_TON_HPEN (0x3 << ICDC_SR_HPST_BIT) /* HP enable state in turn-on */ + #define ICDC_SR_HPST_TOFF_HPEN (0x4 << ICDC_SR_HPST_BIT) /* HP enable state in turn-off */ + #define ICDC_SR_HPST_TOFF_PRE (0x5 << ICDC_SR_HPST_BIT) /* pre-enable state in turn-off */ + #define ICDC_SR_HPST_TOFF_WAIT (0x6 << ICDC_SR_HPST_BIT) /* wait state in turn-off */ + #define ICDC_SR_HPST_HP_ON (0x7 << ICDC_SR_HPST_BIT) /* HP amplifier is on */ +#define ICDC_SR_SNCNT_BIT 0 /* Sample Number Counter */ +#define ICDC_SR_SNCNT_MASK (0x3fff << ICDC_SR_SNCNT_BIT) + +#define ICDC_CDCCR1_ELININ (1 << 29) +#define ICDC_CDCCR1_EMIC (1 << 28) +#define ICDC_CDCCR1_SW1ON (1 << 27) +#define ICDC_CDCCR1_EADC (1 << 26) +#define ICDC_CDCCR1_SW2ON (1 << 25) +#define ICDC_CDCCR1_EDAC (1 << 24) +#define ICDC_CDCCR1_PDVR (1 << 20) +#define ICDC_CDCCR1_PDVRA (1 << 19) +#define ICDC_CDCCR1_VRPLD (1 << 18) +#define ICDC_CDCCR1_VRCGL (1 << 17) +#define ICDC_CDCCR1_VRCGH (1 << 16) +#define ICDC_CDCCR1_HPMUTE (1 << 14) +#define ICDC_CDCCR1_HPOV0 (1 << 13) +#define ICDC_CDCCR1_HPCG (1 << 12) +#define ICDC_CDCCR1_HPPLDM (1 << 11) +#define ICDC_CDCCR1_HPPLDR (1 << 10) +#define ICDC_CDCCR1_PDHPM (1 << 9) +#define ICDC_CDCCR1_PDHP (1 << 8) +#define ICDC_CDCCR1_SUSPD (1 << 1) +#define ICDC_CDCCR1_RST (1 << 0) + +#define ICDC_CDCCR2_AINVOL(n) ((n & 0x1F) << 16) +#define ICDC_CDCCR2_SMPR(n) ((n & 0xF) << 8) +#define ICDC_CDCCR2_MICBG(n) ((n & 0x3) << 4) +#define ICDC_CDCCR2_HPVOL(n) ((n & 0x3) << 0) + +#define ICDC_CDCCR2_SMPR_8 (0) +#define ICDC_CDCCR2_SMPR_11 (1) +#define ICDC_CDCCR2_SMPR_12 (2) +#define ICDC_CDCCR2_SMPR_16 (3) +#define ICDC_CDCCR2_SMPR_22 (4) +#define ICDC_CDCCR2_SMPR_24 (5) +#define ICDC_CDCCR2_SMPR_32 (6) +#define ICDC_CDCCR2_SMPR_44 (7) +#define ICDC_CDCCR2_SMPR_48 (8) + +#define ICDC_CDCCR2_HPVOL_0 (0) +#define ICDC_CDCCR2_HPVOL_2 (1) +#define ICDC_CDCCR2_HPVOL_4 (2) +#define ICDC_CDCCR2_HPVOL_6 (3) + + +/************************************************************************* + * I2C + *************************************************************************/ +#define I2C_DR (I2C_BASE + 0x000) +#define I2C_CR (I2C_BASE + 0x004) +#define I2C_SR (I2C_BASE + 0x008) +#define I2C_GR (I2C_BASE + 0x00C) + +#define REG_I2C_DR REG8(I2C_DR) +#define REG_I2C_CR REG8(I2C_CR) +#define REG_I2C_SR REG8(I2C_SR) +#define REG_I2C_GR REG16(I2C_GR) + +/* I2C Control Register (I2C_CR) */ + +#define I2C_CR_IEN (1 << 4) +#define I2C_CR_STA (1 << 3) +#define I2C_CR_STO (1 << 2) +#define I2C_CR_AC (1 << 1) +#define I2C_CR_I2CE (1 << 0) + +/* I2C Status Register (I2C_SR) */ + +#define I2C_SR_STX (1 << 4) +#define I2C_SR_BUSY (1 << 3) +#define I2C_SR_TEND (1 << 2) +#define I2C_SR_DRF (1 << 1) +#define I2C_SR_ACKF (1 << 0) + + +/************************************************************************* + * SSI + *************************************************************************/ +#define SSI_DR (SSI_BASE + 0x000) +#define SSI_CR0 (SSI_BASE + 0x004) +#define SSI_CR1 (SSI_BASE + 0x008) +#define SSI_SR (SSI_BASE + 0x00C) +#define SSI_ITR (SSI_BASE + 0x010) +#define SSI_ICR (SSI_BASE + 0x014) +#define SSI_GR (SSI_BASE + 0x018) + +#define REG_SSI_DR REG32(SSI_DR) +#define REG_SSI_CR0 REG16(SSI_CR0) +#define REG_SSI_CR1 REG32(SSI_CR1) +#define REG_SSI_SR REG32(SSI_SR) +#define REG_SSI_ITR REG16(SSI_ITR) +#define REG_SSI_ICR REG8(SSI_ICR) +#define REG_SSI_GR REG16(SSI_GR) + +/* SSI Data Register (SSI_DR) */ + +#define SSI_DR_GPC_BIT 0 +#define SSI_DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT) + +/* SSI Control Register 0 (SSI_CR0) */ + +#define SSI_CR0_SSIE (1 << 15) +#define SSI_CR0_TIE (1 << 14) +#define SSI_CR0_RIE (1 << 13) +#define SSI_CR0_TEIE (1 << 12) +#define SSI_CR0_REIE (1 << 11) +#define SSI_CR0_LOOP (1 << 10) +#define SSI_CR0_RFINE (1 << 9) +#define SSI_CR0_RFINC (1 << 8) +#define SSI_CR0_FSEL (1 << 6) +#define SSI_CR0_TFLUSH (1 << 2) +#define SSI_CR0_RFLUSH (1 << 1) +#define SSI_CR0_DISREV (1 << 0) + +/* SSI Control Register 1 (SSI_CR1) */ + +#define SSI_CR1_FRMHL_BIT 30 +#define SSI_CR1_FRMHL_MASK (0x3 << SSI_CR1_FRMHL_BIT) + #define SSI_CR1_FRMHL_CELOW_CE2LOW (0 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */ + #define SSI_CR1_FRMHL_CEHIGH_CE2LOW (1 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */ + #define SSI_CR1_FRMHL_CELOW_CE2HIGH (2 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */ + #define SSI_CR1_FRMHL_CEHIGH_CE2HIGH (3 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */ +#define SSI_CR1_TFVCK_BIT 28 +#define SSI_CR1_TFVCK_MASK (0x3 << SSI_CR1_TFVCK_BIT) + #define SSI_CR1_TFVCK_0 (0 << SSI_CR1_TFVCK_BIT) + #define SSI_CR1_TFVCK_1 (1 << SSI_CR1_TFVCK_BIT) + #define SSI_CR1_TFVCK_2 (2 << SSI_CR1_TFVCK_BIT) + #define SSI_CR1_TFVCK_3 (3 << SSI_CR1_TFVCK_BIT) +#define SSI_CR1_TCKFI_BIT 26 +#define SSI_CR1_TCKFI_MASK (0x3 << SSI_CR1_TCKFI_BIT) + #define SSI_CR1_TCKFI_0 (0 << SSI_CR1_TCKFI_BIT) + #define SSI_CR1_TCKFI_1 (1 << SSI_CR1_TCKFI_BIT) + #define SSI_CR1_TCKFI_2 (2 << SSI_CR1_TCKFI_BIT) + #define SSI_CR1_TCKFI_3 (3 << SSI_CR1_TCKFI_BIT) +#define SSI_CR1_LFST (1 << 25) +#define SSI_CR1_ITFRM (1 << 24) +#define SSI_CR1_UNFIN (1 << 23) +#define SSI_CR1_MULTS (1 << 22) +#define SSI_CR1_FMAT_BIT 20 +#define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT) + #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */ + #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */ + #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */ + #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */ +#define SSI_CR1_TTRG_BIT 16 +#define SSI_CR1_TTRG_MASK (0xf << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_1 (0 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_8 (1 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_16 (2 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_24 (3 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_32 (4 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_40 (5 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_48 (6 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_56 (7 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_64 (8 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_72 (9 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_80 (10<< SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_88 (11<< SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_96 (12<< SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_104 (13<< SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_112 (14<< SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_120 (15<< SSI_CR1_TTRG_BIT) +#define SSI_CR1_MCOM_BIT 12 +#define SSI_CR1_MCOM_MASK (0xf << SSI_CR1_MCOM_BIT) + #define SSI_CR1_MCOM_1BIT (0x0 << SSI_CR1_MCOM_BIT) /* 1-bit command selected */ + #define SSI_CR1_MCOM_2BIT (0x1 << SSI_CR1_MCOM_BIT) /* 2-bit command selected */ + #define SSI_CR1_MCOM_3BIT (0x2 << SSI_CR1_MCOM_BIT) /* 3-bit command selected */ + #define SSI_CR1_MCOM_4BIT (0x3 << SSI_CR1_MCOM_BIT) /* 4-bit command selected */ + #define SSI_CR1_MCOM_5BIT (0x4 << SSI_CR1_MCOM_BIT) /* 5-bit command selected */ + #define SSI_CR1_MCOM_6BIT (0x5 << SSI_CR1_MCOM_BIT) /* 6-bit command selected */ + #define SSI_CR1_MCOM_7BIT (0x6 << SSI_CR1_MCOM_BIT) /* 7-bit command selected */ + #define SSI_CR1_MCOM_8BIT (0x7 << SSI_CR1_MCOM_BIT) /* 8-bit command selected */ + #define SSI_CR1_MCOM_9BIT (0x8 << SSI_CR1_MCOM_BIT) /* 9-bit command selected */ + #define SSI_CR1_MCOM_10BIT (0x9 << SSI_CR1_MCOM_BIT) /* 10-bit command selected */ + #define SSI_CR1_MCOM_11BIT (0xA << SSI_CR1_MCOM_BIT) /* 11-bit command selected */ + #define SSI_CR1_MCOM_12BIT (0xB << SSI_CR1_MCOM_BIT) /* 12-bit command selected */ + #define SSI_CR1_MCOM_13BIT (0xC << SSI_CR1_MCOM_BIT) /* 13-bit command selected */ + #define SSI_CR1_MCOM_14BIT (0xD << SSI_CR1_MCOM_BIT) /* 14-bit command selected */ + #define SSI_CR1_MCOM_15BIT (0xE << SSI_CR1_MCOM_BIT) /* 15-bit command selected */ + #define SSI_CR1_MCOM_16BIT (0xF << SSI_CR1_MCOM_BIT) /* 16-bit command selected */ +#define SSI_CR1_RTRG_BIT 8 +#define SSI_CR1_RTRG_MASK (0xf << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_1 (0 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_8 (1 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_16 (2 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_24 (3 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_32 (4 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_40 (5 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_48 (6 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_56 (7 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_64 (8 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_72 (9 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_80 (10<< SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_88 (11<< SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_96 (12<< SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_104 (13<< SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_112 (14<< SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_120 (15<< SSI_CR1_RTRG_BIT) +#define SSI_CR1_FLEN_BIT 4 +#define SSI_CR1_FLEN_MASK (0xf << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_2BIT (0x0 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_3BIT (0x1 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_4BIT (0x2 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_5BIT (0x3 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_6BIT (0x4 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_7BIT (0x5 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_8BIT (0x6 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_9BIT (0x7 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_10BIT (0x8 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_11BIT (0x9 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_12BIT (0xA << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_13BIT (0xB << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_14BIT (0xC << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_15BIT (0xD << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_16BIT (0xE << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_17BIT (0xF << SSI_CR1_FLEN_BIT) +#define SSI_CR1_PHA (1 << 1) +#define SSI_CR1_POL (1 << 0) + +/* SSI Status Register (SSI_SR) */ + +#define SSI_SR_TFIFONUM_BIT 16 +#define SSI_SR_TFIFONUM_MASK (0xff << SSI_SR_TFIFONUM_BIT) +#define SSI_SR_RFIFONUM_BIT 8 +#define SSI_SR_RFIFONUM_MASK (0xff << SSI_SR_RFIFONUM_BIT) +#define SSI_SR_END (1 << 7) +#define SSI_SR_BUSY (1 << 6) +#define SSI_SR_TFF (1 << 5) +#define SSI_SR_RFE (1 << 4) +#define SSI_SR_TFHE (1 << 3) +#define SSI_SR_RFHF (1 << 2) +#define SSI_SR_UNDR (1 << 1) +#define SSI_SR_OVER (1 << 0) + +/* SSI Interval Time Control Register (SSI_ITR) */ + +#define SSI_ITR_CNTCLK (1 << 15) +#define SSI_ITR_IVLTM_BIT 0 +#define SSI_ITR_IVLTM_MASK (0x7fff << SSI_ITR_IVLTM_BIT) + + +/************************************************************************* + * MSC + *************************************************************************/ +#define MSC_STRPCL (MSC_BASE + 0x000) +#define MSC_STAT (MSC_BASE + 0x004) +#define MSC_CLKRT (MSC_BASE + 0x008) +#define MSC_CMDAT (MSC_BASE + 0x00C) +#define MSC_RESTO (MSC_BASE + 0x010) +#define MSC_RDTO (MSC_BASE + 0x014) +#define MSC_BLKLEN (MSC_BASE + 0x018) +#define MSC_NOB (MSC_BASE + 0x01C) +#define MSC_SNOB (MSC_BASE + 0x020) +#define MSC_IMASK (MSC_BASE + 0x024) +#define MSC_IREG (MSC_BASE + 0x028) +#define MSC_CMD (MSC_BASE + 0x02C) +#define MSC_ARG (MSC_BASE + 0x030) +#define MSC_RES (MSC_BASE + 0x034) +#define MSC_RXFIFO (MSC_BASE + 0x038) +#define MSC_TXFIFO (MSC_BASE + 0x03C) + +#define REG_MSC_STRPCL REG16(MSC_STRPCL) +#define REG_MSC_STAT REG32(MSC_STAT) +#define REG_MSC_CLKRT REG16(MSC_CLKRT) +#define REG_MSC_CMDAT REG32(MSC_CMDAT) +#define REG_MSC_RESTO REG16(MSC_RESTO) +#define REG_MSC_RDTO REG16(MSC_RDTO) +#define REG_MSC_BLKLEN REG16(MSC_BLKLEN) +#define REG_MSC_NOB REG16(MSC_NOB) +#define REG_MSC_SNOB REG16(MSC_SNOB) +#define REG_MSC_IMASK REG16(MSC_IMASK) +#define REG_MSC_IREG REG16(MSC_IREG) +#define REG_MSC_CMD REG8(MSC_CMD) +#define REG_MSC_ARG REG32(MSC_ARG) +#define REG_MSC_RES REG16(MSC_RES) +#define REG_MSC_RXFIFO REG32(MSC_RXFIFO) +#define REG_MSC_TXFIFO REG32(MSC_TXFIFO) + +/* MSC Clock and Control Register (MSC_STRPCL) */ + +#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7) +#define MSC_STRPCL_EXIT_TRANSFER (1 << 6) +#define MSC_STRPCL_START_READWAIT (1 << 5) +#define MSC_STRPCL_STOP_READWAIT (1 << 4) +#define MSC_STRPCL_RESET (1 << 3) +#define MSC_STRPCL_START_OP (1 << 2) +#define MSC_STRPCL_CLOCK_CONTROL_BIT 0 +#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT) + #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */ + #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */ + +/* MSC Status Register (MSC_STAT) */ + +#define MSC_STAT_IS_RESETTING (1 << 15) +#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14) +#define MSC_STAT_PRG_DONE (1 << 13) +#define MSC_STAT_DATA_TRAN_DONE (1 << 12) +#define MSC_STAT_END_CMD_RES (1 << 11) +#define MSC_STAT_DATA_FIFO_AFULL (1 << 10) +#define MSC_STAT_IS_READWAIT (1 << 9) +#define MSC_STAT_CLK_EN (1 << 8) +#define MSC_STAT_DATA_FIFO_FULL (1 << 7) +#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6) +#define MSC_STAT_CRC_RES_ERR (1 << 5) +#define MSC_STAT_CRC_READ_ERROR (1 << 4) +#define MSC_STAT_CRC_WRITE_ERROR_BIT 2 +#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT) + #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */ + #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */ + #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */ +#define MSC_STAT_TIME_OUT_RES (1 << 1) +#define MSC_STAT_TIME_OUT_READ (1 << 0) + +/* MSC Bus Clock Control Register (MSC_CLKRT) */ + +#define MSC_CLKRT_CLK_RATE_BIT 0 +#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT) + #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */ + #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */ + #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */ + #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */ + #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */ + #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */ + #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */ + #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */ + +/* MSC Command Sequence Control Register (MSC_CMDAT) */ + +#define MSC_CMDAT_IO_ABORT (1 << 11) +#define MSC_CMDAT_BUS_WIDTH_BIT 9 +#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) + #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) /* 1-bit data bus */ + #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) /* 4-bit data bus */ + #define CMDAT_BUS_WIDTH1 (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) + #define CMDAT_BUS_WIDTH4 (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) +#define MSC_CMDAT_DMA_EN (1 << 8) +#define MSC_CMDAT_INIT (1 << 7) +#define MSC_CMDAT_BUSY (1 << 6) +#define MSC_CMDAT_STREAM_BLOCK (1 << 5) +#define MSC_CMDAT_WRITE (1 << 4) +#define MSC_CMDAT_READ (0 << 4) +#define MSC_CMDAT_DATA_EN (1 << 3) +#define MSC_CMDAT_RESPONSE_BIT 0 +#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT) + #define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT) /* No response */ + #define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT) /* Format R1 and R1b */ + #define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT) /* Format R2 */ + #define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT) /* Format R3 */ + #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) /* Format R4 */ + #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) /* Format R5 */ + #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) /* Format R6 */ + +#define CMDAT_DMA_EN (1 << 8) +#define CMDAT_INIT (1 << 7) +#define CMDAT_BUSY (1 << 6) +#define CMDAT_STREAM (1 << 5) +#define CMDAT_WRITE (1 << 4) +#define CMDAT_DATA_EN (1 << 3) + +/* MSC Interrupts Mask Register (MSC_IMASK) */ + +#define MSC_IMASK_SDIO (1 << 7) +#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6) +#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5) +#define MSC_IMASK_END_CMD_RES (1 << 2) +#define MSC_IMASK_PRG_DONE (1 << 1) +#define MSC_IMASK_DATA_TRAN_DONE (1 << 0) + + +/* MSC Interrupts Status Register (MSC_IREG) */ + +#define MSC_IREG_SDIO (1 << 7) +#define MSC_IREG_TXFIFO_WR_REQ (1 << 6) +#define MSC_IREG_RXFIFO_RD_REQ (1 << 5) +#define MSC_IREG_END_CMD_RES (1 << 2) +#define MSC_IREG_PRG_DONE (1 << 1) +#define MSC_IREG_DATA_TRAN_DONE (1 << 0) + + +/************************************************************************* + * EMC (External Memory Controller) + *************************************************************************/ +#define EMC_BCR (EMC_BASE + 0x0) /* BCR */ + +#define EMC_SMCR0 (EMC_BASE + 0x10) /* Static Memory Control Register 0 */ +#define EMC_SMCR1 (EMC_BASE + 0x14) /* Static Memory Control Register 1 */ +#define EMC_SMCR2 (EMC_BASE + 0x18) /* Static Memory Control Register 2 */ +#define EMC_SMCR3 (EMC_BASE + 0x1c) /* Static Memory Control Register 3 */ +#define EMC_SMCR4 (EMC_BASE + 0x20) /* Static Memory Control Register 4 */ +#define EMC_SACR0 (EMC_BASE + 0x30) /* Static Memory Bank 0 Addr Config Reg */ +#define EMC_SACR1 (EMC_BASE + 0x34) /* Static Memory Bank 1 Addr Config Reg */ +#define EMC_SACR2 (EMC_BASE + 0x38) /* Static Memory Bank 2 Addr Config Reg */ +#define EMC_SACR3 (EMC_BASE + 0x3c) /* Static Memory Bank 3 Addr Config Reg */ +#define EMC_SACR4 (EMC_BASE + 0x40) /* Static Memory Bank 4 Addr Config Reg */ + +#define EMC_NFCSR (EMC_BASE + 0x050) /* NAND Flash Control/Status Register */ +#define EMC_NFECR (EMC_BASE + 0x100) /* NAND Flash ECC Control Register */ +#define EMC_NFECC (EMC_BASE + 0x104) /* NAND Flash ECC Data Register */ +#define EMC_NFPAR0 (EMC_BASE + 0x108) /* NAND Flash RS Parity 0 Register */ +#define EMC_NFPAR1 (EMC_BASE + 0x10c) /* NAND Flash RS Parity 1 Register */ +#define EMC_NFPAR2 (EMC_BASE + 0x110) /* NAND Flash RS Parity 2 Register */ +#define EMC_NFINTS (EMC_BASE + 0x114) /* NAND Flash Interrupt Status Register */ +#define EMC_NFINTE (EMC_BASE + 0x118) /* NAND Flash Interrupt Enable Register */ +#define EMC_NFERR0 (EMC_BASE + 0x11c) /* NAND Flash RS Error Report 0 Register */ +#define EMC_NFERR1 (EMC_BASE + 0x120) /* NAND Flash RS Error Report 1 Register */ +#define EMC_NFERR2 (EMC_BASE + 0x124) /* NAND Flash RS Error Report 2 Register */ +#define EMC_NFERR3 (EMC_BASE + 0x128) /* NAND Flash RS Error Report 3 Register */ + +#define EMC_DMCR (EMC_BASE + 0x80) /* DRAM Control Register */ +#define EMC_RTCSR (EMC_BASE + 0x84) /* Refresh Time Control/Status Register */ +#define EMC_RTCNT (EMC_BASE + 0x88) /* Refresh Timer Counter */ +#define EMC_RTCOR (EMC_BASE + 0x8c) /* Refresh Time Constant Register */ +#define EMC_DMAR0 (EMC_BASE + 0x90) /* SDRAM Bank 0 Addr Config Register */ +#define EMC_SDMR0 (EMC_BASE + 0xa000) /* Mode Register of SDRAM bank 0 */ + +#define REG_EMC_BCR REG32(EMC_BCR) + +#define REG_EMC_SMCR0 REG32(EMC_SMCR0) +#define REG_EMC_SMCR1 REG32(EMC_SMCR1) +#define REG_EMC_SMCR2 REG32(EMC_SMCR2) +#define REG_EMC_SMCR3 REG32(EMC_SMCR3) +#define REG_EMC_SMCR4 REG32(EMC_SMCR4) +#define REG_EMC_SACR0 REG32(EMC_SACR0) +#define REG_EMC_SACR1 REG32(EMC_SACR1) +#define REG_EMC_SACR2 REG32(EMC_SACR2) +#define REG_EMC_SACR3 REG32(EMC_SACR3) +#define REG_EMC_SACR4 REG32(EMC_SACR4) + +#define REG_EMC_NFCSR REG32(EMC_NFCSR) +#define REG_EMC_NFECR REG32(EMC_NFECR) +#define REG_EMC_NFECC REG32(EMC_NFECC) +#define REG_EMC_NFPAR0 REG32(EMC_NFPAR0) +#define REG_EMC_NFPAR1 REG32(EMC_NFPAR1) +#define REG_EMC_NFPAR2 REG32(EMC_NFPAR2) +#define REG_EMC_NFINTS REG32(EMC_NFINTS) +#define REG_EMC_NFINTE REG32(EMC_NFINTE) +#define REG_EMC_NFERR0 REG32(EMC_NFERR0) +#define REG_EMC_NFERR1 REG32(EMC_NFERR1) +#define REG_EMC_NFERR2 REG32(EMC_NFERR2) +#define REG_EMC_NFERR3 REG32(EMC_NFERR3) + +#define REG_EMC_DMCR REG32(EMC_DMCR) +#define REG_EMC_RTCSR REG16(EMC_RTCSR) +#define REG_EMC_RTCNT REG16(EMC_RTCNT) +#define REG_EMC_RTCOR REG16(EMC_RTCOR) +#define REG_EMC_DMAR0 REG32(EMC_DMAR0) + +/* Static Memory Control Register */ +#define EMC_SMCR_STRV_BIT 24 +#define EMC_SMCR_STRV_MASK (0x0f << EMC_SMCR_STRV_BIT) +#define EMC_SMCR_TAW_BIT 20 +#define EMC_SMCR_TAW_MASK (0x0f << EMC_SMCR_TAW_BIT) +#define EMC_SMCR_TBP_BIT 16 +#define EMC_SMCR_TBP_MASK (0x0f << EMC_SMCR_TBP_BIT) +#define EMC_SMCR_TAH_BIT 12 +#define EMC_SMCR_TAH_MASK (0x07 << EMC_SMCR_TAH_BIT) +#define EMC_SMCR_TAS_BIT 8 +#define EMC_SMCR_TAS_MASK (0x07 << EMC_SMCR_TAS_BIT) +#define EMC_SMCR_BW_BIT 6 +#define EMC_SMCR_BW_MASK (0x03 << EMC_SMCR_BW_BIT) /* Bus Width? */ + #define EMC_SMCR_BW_8BIT (0 << EMC_SMCR_BW_BIT) + #define EMC_SMCR_BW_16BIT (1 << EMC_SMCR_BW_BIT) + #define EMC_SMCR_BW_32BIT (2 << EMC_SMCR_BW_BIT) +#define EMC_SMCR_BCM (1 << 3) +#define EMC_SMCR_BL_BIT 1 +#define EMC_SMCR_BL_MASK (0x03 << EMC_SMCR_BL_BIT) /* Bus Latency? */ + #define EMC_SMCR_BL_4 (0 << EMC_SMCR_BL_BIT) + #define EMC_SMCR_BL_8 (1 << EMC_SMCR_BL_BIT) + #define EMC_SMCR_BL_16 (2 << EMC_SMCR_BL_BIT) + #define EMC_SMCR_BL_32 (3 << EMC_SMCR_BL_BIT) +#define EMC_SMCR_SMT (1 << 0) + +/* Static Memory Bank Addr Config Reg */ +#define EMC_SACR_BASE_BIT 8 +#define EMC_SACR_BASE_MASK (0xff << EMC_SACR_BASE_BIT) +#define EMC_SACR_MASK_BIT 0 +#define EMC_SACR_MASK_MASK (0xff << EMC_SACR_MASK_BIT) + +/* NAND Flash Control/Status Register */ +#define EMC_NFCSR_NFCE4 (1 << 7) /* NAND Flash Enable */ +#define EMC_NFCSR_NFE4 (1 << 6) /* NAND Flash FCE# Assertion Enable */ +#define EMC_NFCSR_NFCE3 (1 << 5) +#define EMC_NFCSR_NFE3 (1 << 4) +#define EMC_NFCSR_NFCE2 (1 << 3) +#define EMC_NFCSR_NFE2 (1 << 2) +#define EMC_NFCSR_NFCE1 (1 << 1) +#define EMC_NFCSR_NFE1 (1 << 0) +#define EMC_NFCSR_NFE(n) (1 << (((n)-1)*2)) +#define EMC_NFCSR_NFCE(n) (1 << (((n)*2)-1)) + +/* NAND Flash ECC Control Register */ +#define EMC_NFECR_PRDY (1 << 4) /* Parity Ready */ +#define EMC_NFECR_RS_DECODING (0 << 3) /* RS is in decoding phase */ +#define EMC_NFECR_RS_ENCODING (1 << 3) /* RS is in encoding phase */ +#define EMC_NFECR_HAMMING (0 << 2) /* Select HAMMING Correction Algorithm */ +#define EMC_NFECR_RS (1 << 2) /* Select RS Correction Algorithm */ +#define EMC_NFECR_ERST (1 << 1) /* ECC Reset */ +#define EMC_NFECR_ECCE (1 << 0) /* ECC Enable */ + +/* NAND Flash ECC Data Register */ +#define EMC_NFECC_ECC2_BIT 16 +#define EMC_NFECC_ECC2_MASK (0xff << EMC_NFECC_ECC2_BIT) +#define EMC_NFECC_ECC1_BIT 8 +#define EMC_NFECC_ECC1_MASK (0xff << EMC_NFECC_ECC1_BIT) +#define EMC_NFECC_ECC0_BIT 0 +#define EMC_NFECC_ECC0_MASK (0xff << EMC_NFECC_ECC0_BIT) + +/* NAND Flash Interrupt Status Register */ +#define EMC_NFINTS_ERRCNT_BIT 29 /* Error Count */ +#define EMC_NFINTS_ERRCNT_MASK (0x7 << EMC_NFINTS_ERRCNT_BIT) +#define EMC_NFINTS_PADF (1 << 4) /* Padding Finished */ +#define EMC_NFINTS_DECF (1 << 3) /* Decoding Finished */ +#define EMC_NFINTS_ENCF (1 << 2) /* Encoding Finished */ +#define EMC_NFINTS_UNCOR (1 << 1) /* Uncorrectable Error Occurred */ +#define EMC_NFINTS_ERR (1 << 0) /* Error Occurred */ + +/* NAND Flash Interrupt Enable Register */ +#define EMC_NFINTE_PADFE (1 << 4) /* Padding Finished Interrupt Enable */ +#define EMC_NFINTE_DECFE (1 << 3) /* Decoding Finished Interrupt Enable */ +#define EMC_NFINTE_ENCFE (1 << 2) /* Encoding Finished Interrupt Enable */ +#define EMC_NFINTE_UNCORE (1 << 1) /* Uncorrectable Error Occurred Intr Enable */ +#define EMC_NFINTE_ERRE (1 << 0) /* Error Occurred Interrupt */ + +/* NAND Flash RS Error Report Register */ +#define EMC_NFERR_INDEX_BIT 16 /* Error Symbol Index */ +#define EMC_NFERR_INDEX_MASK (0x1ff << EMC_NFERR_INDEX_BIT) +#define EMC_NFERR_MASK_BIT 0 /* Error Symbol Value */ +#define EMC_NFERR_MASK_MASK (0x1ff << EMC_NFERR_MASK_BIT) + + +/* DRAM Control Register */ +#define EMC_DMCR_BW_BIT 31 +#define EMC_DMCR_BW (1 << EMC_DMCR_BW_BIT) +#define EMC_DMCR_CA_BIT 26 +#define EMC_DMCR_CA_MASK (0x07 << EMC_DMCR_CA_BIT) + #define EMC_DMCR_CA_8 (0 << EMC_DMCR_CA_BIT) + #define EMC_DMCR_CA_9 (1 << EMC_DMCR_CA_BIT) + #define EMC_DMCR_CA_10 (2 << EMC_DMCR_CA_BIT) + #define EMC_DMCR_CA_11 (3 << EMC_DMCR_CA_BIT) + #define EMC_DMCR_CA_12 (4 << EMC_DMCR_CA_BIT) +#define EMC_DMCR_RMODE (1 << 25) +#define EMC_DMCR_RFSH (1 << 24) +#define EMC_DMCR_MRSET (1 << 23) +#define EMC_DMCR_RA_BIT 20 +#define EMC_DMCR_RA_MASK (0x03 << EMC_DMCR_RA_BIT) + #define EMC_DMCR_RA_11 (0 << EMC_DMCR_RA_BIT) + #define EMC_DMCR_RA_12 (1 << EMC_DMCR_RA_BIT) + #define EMC_DMCR_RA_13 (2 << EMC_DMCR_RA_BIT) +#define EMC_DMCR_BA_BIT 19 +#define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT) +#define EMC_DMCR_PDM (1 << 18) +#define EMC_DMCR_EPIN (1 << 17) +#define EMC_DMCR_TRAS_BIT 13 +#define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT) +#define EMC_DMCR_RCD_BIT 11 +#define EMC_DMCR_RCD_MASK (0x03 << EMC_DMCR_RCD_BIT) +#define EMC_DMCR_TPC_BIT 8 +#define EMC_DMCR_TPC_MASK (0x07 << EMC_DMCR_TPC_BIT) +#define EMC_DMCR_TRWL_BIT 5 +#define EMC_DMCR_TRWL_MASK (0x03 << EMC_DMCR_TRWL_BIT) +#define EMC_DMCR_TRC_BIT 2 +#define EMC_DMCR_TRC_MASK (0x07 << EMC_DMCR_TRC_BIT) +#define EMC_DMCR_TCL_BIT 0 +#define EMC_DMCR_TCL_MASK (0x03 << EMC_DMCR_TCL_BIT) + +/* Refresh Time Control/Status Register */ +#define EMC_RTCSR_CMF (1 << 7) +#define EMC_RTCSR_CKS_BIT 0 +#define EMC_RTCSR_CKS_MASK (0x07 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_DISABLE (0 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_4 (1 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_16 (2 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_64 (3 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_256 (4 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_1024 (5 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_2048 (6 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_4096 (7 << EMC_RTCSR_CKS_BIT) + +/* SDRAM Bank Address Configuration Register */ +#define EMC_DMAR_BASE_BIT 8 +#define EMC_DMAR_BASE_MASK (0xff << EMC_DMAR_BASE_BIT) +#define EMC_DMAR_MASK_BIT 0 +#define EMC_DMAR_MASK_MASK (0xff << EMC_DMAR_MASK_BIT) + +/* Mode Register of SDRAM bank 0 */ +#define EMC_SDMR_BM (1 << 9) /* Write Burst Mode */ +#define EMC_SDMR_OM_BIT 7 /* Operating Mode */ +#define EMC_SDMR_OM_MASK (3 << EMC_SDMR_OM_BIT) + #define EMC_SDMR_OM_NORMAL (0 << EMC_SDMR_OM_BIT) +#define EMC_SDMR_CAS_BIT 4 /* CAS Latency */ +#define EMC_SDMR_CAS_MASK (7 << EMC_SDMR_CAS_BIT) + #define EMC_SDMR_CAS_1 (1 << EMC_SDMR_CAS_BIT) + #define EMC_SDMR_CAS_2 (2 << EMC_SDMR_CAS_BIT) + #define EMC_SDMR_CAS_3 (3 << EMC_SDMR_CAS_BIT) +#define EMC_SDMR_BT_BIT 3 /* Burst Type */ +#define EMC_SDMR_BT_MASK (1 << EMC_SDMR_BT_BIT) + #define EMC_SDMR_BT_SEQ (0 << EMC_SDMR_BT_BIT) /* Sequential */ + #define EMC_SDMR_BT_INT (1 << EMC_SDMR_BT_BIT) /* Interleave */ +#define EMC_SDMR_BL_BIT 0 /* Burst Length */ +#define EMC_SDMR_BL_MASK (7 << EMC_SDMR_BL_BIT) + #define EMC_SDMR_BL_1 (0 << EMC_SDMR_BL_BIT) + #define EMC_SDMR_BL_2 (1 << EMC_SDMR_BL_BIT) + #define EMC_SDMR_BL_4 (2 << EMC_SDMR_BL_BIT) + #define EMC_SDMR_BL_8 (3 << EMC_SDMR_BL_BIT) + +#define EMC_SDMR_CAS2_16BIT \ + (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) +#define EMC_SDMR_CAS2_32BIT \ + (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) +#define EMC_SDMR_CAS3_16BIT \ + (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) +#define EMC_SDMR_CAS3_32BIT \ + (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) + + +/************************************************************************* + * CIM + *************************************************************************/ +#define CIM_CFG (CIM_BASE + 0x0000) +#define CIM_CTRL (CIM_BASE + 0x0004) +#define CIM_STATE (CIM_BASE + 0x0008) +#define CIM_IID (CIM_BASE + 0x000C) +#define CIM_RXFIFO (CIM_BASE + 0x0010) +#define CIM_DA (CIM_BASE + 0x0020) +#define CIM_FA (CIM_BASE + 0x0024) +#define CIM_FID (CIM_BASE + 0x0028) +#define CIM_CMD (CIM_BASE + 0x002C) + +#define REG_CIM_CFG REG32(CIM_CFG) +#define REG_CIM_CTRL REG32(CIM_CTRL) +#define REG_CIM_STATE REG32(CIM_STATE) +#define REG_CIM_IID REG32(CIM_IID) +#define REG_CIM_RXFIFO REG32(CIM_RXFIFO) +#define REG_CIM_DA REG32(CIM_DA) +#define REG_CIM_FA REG32(CIM_FA) +#define REG_CIM_FID REG32(CIM_FID) +#define REG_CIM_CMD REG32(CIM_CMD) + +/* CIM Configuration Register (CIM_CFG) */ + +#define CIM_CFG_INV_DAT (1 << 15) +#define CIM_CFG_VSP (1 << 14) +#define CIM_CFG_HSP (1 << 13) +#define CIM_CFG_PCP (1 << 12) +#define CIM_CFG_DUMMY_ZERO (1 << 9) +#define CIM_CFG_EXT_VSYNC (1 << 8) +#define CIM_CFG_PACK_BIT 4 +#define CIM_CFG_PACK_MASK (0x7 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_0 (0 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_1 (1 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_2 (2 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_3 (3 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_4 (4 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_5 (5 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_6 (6 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_7 (7 << CIM_CFG_PACK_BIT) +#define CIM_CFG_DSM_BIT 0 +#define CIM_CFG_DSM_MASK (0x3 << CIM_CFG_DSM_BIT) + #define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM_BIT) /* CCIR656 Progressive Mode */ + #define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM_BIT) /* CCIR656 Interlace Mode */ + #define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM_BIT) /* Gated Clock Mode */ + #define CIM_CFG_DSM_NGCM (3 << CIM_CFG_DSM_BIT) /* Non-Gated Clock Mode */ + +/* CIM Control Register (CIM_CTRL) */ + +#define CIM_CTRL_MCLKDIV_BIT 24 +#define CIM_CTRL_MCLKDIV_MASK (0xff << CIM_CTRL_MCLKDIV_BIT) +#define CIM_CTRL_FRC_BIT 16 +#define CIM_CTRL_FRC_MASK (0xf << CIM_CTRL_FRC_BIT) + #define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every frame */ + #define CIM_CTRL_FRC_2 (0x1 << CIM_CTRL_FRC_BIT) /* Sample 1/2 frame */ + #define CIM_CTRL_FRC_3 (0x2 << CIM_CTRL_FRC_BIT) /* Sample 1/3 frame */ + #define CIM_CTRL_FRC_4 (0x3 << CIM_CTRL_FRC_BIT) /* Sample 1/4 frame */ + #define CIM_CTRL_FRC_5 (0x4 << CIM_CTRL_FRC_BIT) /* Sample 1/5 frame */ + #define CIM_CTRL_FRC_6 (0x5 << CIM_CTRL_FRC_BIT) /* Sample 1/6 frame */ + #define CIM_CTRL_FRC_7 (0x6 << CIM_CTRL_FRC_BIT) /* Sample 1/7 frame */ + #define CIM_CTRL_FRC_8 (0x7 << CIM_CTRL_FRC_BIT) /* Sample 1/8 frame */ + #define CIM_CTRL_FRC_9 (0x8 << CIM_CTRL_FRC_BIT) /* Sample 1/9 frame */ + #define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) /* Sample 1/10 frame */ + #define CIM_CTRL_FRC_11 (0xA << CIM_CTRL_FRC_BIT) /* Sample 1/11 frame */ + #define CIM_CTRL_FRC_12 (0xB << CIM_CTRL_FRC_BIT) /* Sample 1/12 frame */ + #define CIM_CTRL_FRC_13 (0xC << CIM_CTRL_FRC_BIT) /* Sample 1/13 frame */ + #define CIM_CTRL_FRC_14 (0xD << CIM_CTRL_FRC_BIT) /* Sample 1/14 frame */ + #define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */ + #define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */ +#define CIM_CTRL_VDDM (1 << 13) +#define CIM_CTRL_DMA_SOFM (1 << 12) +#define CIM_CTRL_DMA_EOFM (1 << 11) +#define CIM_CTRL_DMA_STOPM (1 << 10) +#define CIM_CTRL_RXF_TRIGM (1 << 9) +#define CIM_CTRL_RXF_OFM (1 << 8) +#define CIM_CTRL_RXF_TRIG_BIT 4 +#define CIM_CTRL_RXF_TRIG_MASK (0x7 << CIM_CTRL_RXF_TRIG_BIT) + #define CIM_CTRL_RXF_TRIG_4 (0 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 4 */ + #define CIM_CTRL_RXF_TRIG_8 (1 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 8 */ + #define CIM_CTRL_RXF_TRIG_12 (2 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 12 */ + #define CIM_CTRL_RXF_TRIG_16 (3 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 16 */ + #define CIM_CTRL_RXF_TRIG_20 (4 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 20 */ + #define CIM_CTRL_RXF_TRIG_24 (5 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 24 */ + #define CIM_CTRL_RXF_TRIG_28 (6 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 28 */ + #define CIM_CTRL_RXF_TRIG_32 (7 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 32 */ +#define CIM_CTRL_DMA_EN (1 << 2) +#define CIM_CTRL_RXF_RST (1 << 1) +#define CIM_CTRL_ENA (1 << 0) + +/* CIM State Register (CIM_STATE) */ + +#define CIM_STATE_DMA_SOF (1 << 6) +#define CIM_STATE_DMA_EOF (1 << 5) +#define CIM_STATE_DMA_STOP (1 << 4) +#define CIM_STATE_RXF_OF (1 << 3) +#define CIM_STATE_RXF_TRIG (1 << 2) +#define CIM_STATE_RXF_EMPTY (1 << 1) +#define CIM_STATE_VDD (1 << 0) + +/* CIM DMA Command Register (CIM_CMD) */ + +#define CIM_CMD_SOFINT (1 << 31) +#define CIM_CMD_EOFINT (1 << 30) +#define CIM_CMD_STOP (1 << 28) +#define CIM_CMD_LEN_BIT 0 +#define CIM_CMD_LEN_MASK (0xffffff << CIM_CMD_LEN_BIT) + + +/************************************************************************* + * SADC (Smart A/D Controller) + *************************************************************************/ + +#define SADC_ENA (SADC_BASE + 0x00) /* ADC Enable Register */ +#define SADC_CFG (SADC_BASE + 0x04) /* ADC Configure Register */ +#define SADC_CTRL (SADC_BASE + 0x08) /* ADC Control Register */ +#define SADC_STATE (SADC_BASE + 0x0C) /* ADC Status Register*/ +#define SADC_SAMETIME (SADC_BASE + 0x10) /* ADC Same Point Time Register */ +#define SADC_WAITTIME (SADC_BASE + 0x14) /* ADC Wait Time Register */ +#define SADC_TSDAT (SADC_BASE + 0x18) /* ADC Touch Screen Data Register */ +#define SADC_BATDAT (SADC_BASE + 0x1C) /* ADC PBAT Data Register */ +#define SADC_SADDAT (SADC_BASE + 0x20) /* ADC SADCIN Data Register */ + +#define REG_SADC_ENA REG8(SADC_ENA) +#define REG_SADC_CFG REG32(SADC_CFG) +#define REG_SADC_CTRL REG8(SADC_CTRL) +#define REG_SADC_STATE REG8(SADC_STATE) +#define REG_SADC_SAMETIME REG16(SADC_SAMETIME) +#define REG_SADC_WAITTIME REG16(SADC_WAITTIME) +#define REG_SADC_TSDAT REG32(SADC_TSDAT) +#define REG_SADC_BATDAT REG16(SADC_BATDAT) +#define REG_SADC_SADDAT REG16(SADC_SADDAT) + +/* ADC Enable Register */ +#define SADC_ENA_ADEN (1 << 7) /* Touch Screen Enable */ +#define SADC_ENA_TSEN (1 << 2) /* Touch Screen Enable */ +#define SADC_ENA_PBATEN (1 << 1) /* PBAT Enable */ +#define SADC_ENA_SADCINEN (1 << 0) /* SADCIN Enable */ + +/* ADC Configure Register */ +#define SADC_CFG_CLKOUT_NUM_BIT 16 +#define SADC_CFG_CLKOUT_NUM_MASK (0x7 << SADC_CFG_CLKOUT_NUM_BIT) +#define SADC_CFG_TS_DMA (1 << 15) /* Touch Screen DMA Enable */ +#define SADC_CFG_XYZ_BIT 13 /* XYZ selection */ +#define SADC_CFG_XYZ_MASK (0x3 << SADC_CFG_XYZ_BIT) + #define SADC_CFG_XY (0 << SADC_CFG_XYZ_BIT) + #define SADC_CFG_XYZ (1 << SADC_CFG_XYZ_BIT) + #define SADC_CFG_XYZ1Z2 (2 << SADC_CFG_XYZ_BIT) +#define SADC_CFG_SNUM_BIT 10 /* Sample Number */ +#define SADC_CFG_SNUM_MASK (0x7 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_1 (0x0 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_2 (0x1 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_3 (0x2 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_4 (0x3 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_5 (0x4 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_6 (0x5 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_8 (0x6 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_9 (0x7 << SADC_CFG_SNUM_BIT) +#define SADC_CFG_CLKDIV_BIT 5 /* AD Converter frequency clock divider */ +#define SADC_CFG_CLKDIV_MASK (0x1f << SADC_CFG_CLKDIV_BIT) +#define SADC_CFG_PBAT_HIGH (0 << 4) /* PBAT >= 2.5V */ +#define SADC_CFG_PBAT_LOW (1 << 4) /* PBAT < 2.5V */ +#define SADC_CFG_CMD_BIT 0 /* ADC Command */ +#define SADC_CFG_CMD_MASK (0xf << SADC_CFG_CMD_BIT) + #define SADC_CFG_CMD_X_SE (0x0 << SADC_CFG_CMD_BIT) /* X Single-End */ + #define SADC_CFG_CMD_Y_SE (0x1 << SADC_CFG_CMD_BIT) /* Y Single-End */ + #define SADC_CFG_CMD_X_DIFF (0x2 << SADC_CFG_CMD_BIT) /* X Differential */ + #define SADC_CFG_CMD_Y_DIFF (0x3 << SADC_CFG_CMD_BIT) /* Y Differential */ + #define SADC_CFG_CMD_Z1_DIFF (0x4 << SADC_CFG_CMD_BIT) /* Z1 Differential */ + #define SADC_CFG_CMD_Z2_DIFF (0x5 << SADC_CFG_CMD_BIT) /* Z2 Differential */ + #define SADC_CFG_CMD_Z3_DIFF (0x6 << SADC_CFG_CMD_BIT) /* Z3 Differential */ + #define SADC_CFG_CMD_Z4_DIFF (0x7 << SADC_CFG_CMD_BIT) /* Z4 Differential */ + #define SADC_CFG_CMD_TP_SE (0x8 << SADC_CFG_CMD_BIT) /* Touch Pressure */ + #define SADC_CFG_CMD_PBATH_SE (0x9 << SADC_CFG_CMD_BIT) /* PBAT >= 2.5V */ + #define SADC_CFG_CMD_PBATL_SE (0xa << SADC_CFG_CMD_BIT) /* PBAT < 2.5V */ + #define SADC_CFG_CMD_SADCIN_SE (0xb << SADC_CFG_CMD_BIT) /* Measure SADCIN */ + #define SADC_CFG_CMD_INT_PEN (0xc << SADC_CFG_CMD_BIT) /* INT_PEN Enable */ + +/* ADC Control Register */ +#define SADC_CTRL_PENDM (1 << 4) /* Pen Down Interrupt Mask */ +#define SADC_CTRL_PENUM (1 << 3) /* Pen Up Interrupt Mask */ +#define SADC_CTRL_TSRDYM (1 << 2) /* Touch Screen Data Ready Interrupt Mask */ +#define SADC_CTRL_PBATRDYM (1 << 1) /* PBAT Data Ready Interrupt Mask */ +#define SADC_CTRL_SRDYM (1 << 0) /* SADCIN Data Ready Interrupt Mask */ + +/* ADC Status Register */ +#define SADC_STATE_TSBUSY (1 << 7) /* TS A/D is working */ +#define SADC_STATE_PBATBUSY (1 << 6) /* PBAT A/D is working */ +#define SADC_STATE_SBUSY (1 << 5) /* SADCIN A/D is working */ +#define SADC_STATE_PEND (1 << 4) /* Pen Down Interrupt Flag */ +#define SADC_STATE_PENU (1 << 3) /* Pen Up Interrupt Flag */ +#define SADC_STATE_TSRDY (1 << 2) /* Touch Screen Data Ready Interrupt Flag */ +#define SADC_STATE_PBATRDY (1 << 1) /* PBAT Data Ready Interrupt Flag */ +#define SADC_STATE_SRDY (1 << 0) /* SADCIN Data Ready Interrupt Flag */ + +/* ADC Touch Screen Data Register */ +#define SADC_TSDAT_DATA0_BIT 0 +#define SADC_TSDAT_DATA0_MASK (0xfff << SADC_TSDAT_DATA0_BIT) +#define SADC_TSDAT_TYPE0 (1 << 15) +#define SADC_TSDAT_DATA1_BIT 16 +#define SADC_TSDAT_DATA1_MASK (0xfff << SADC_TSDAT_DATA1_BIT) +#define SADC_TSDAT_TYPE1 (1 << 31) + + +/************************************************************************* + * SLCD (Smart LCD Controller) + *************************************************************************/ + +#define SLCD_CFG (SLCD_BASE + 0xA0) /* SLCD Configure Register */ +#define SLCD_CTRL (SLCD_BASE + 0xA4) /* SLCD Control Register */ +#define SLCD_STATE (SLCD_BASE + 0xA8) /* SLCD Status Register */ +#define SLCD_DATA (SLCD_BASE + 0xAC) /* SLCD Data Register */ +#define SLCD_FIFO (SLCD_BASE + 0xB0) /* SLCD FIFO Register */ + +#define REG_SLCD_CFG REG32(SLCD_CFG) +#define REG_SLCD_CTRL REG8(SLCD_CTRL) +#define REG_SLCD_STATE REG8(SLCD_STATE) +#define REG_SLCD_DATA REG32(SLCD_DATA) +#define REG_SLCD_FIFO REG32(SLCD_FIFO) + +/* SLCD Configure Register */ +#define SLCD_CFG_BURST_BIT 14 +#define SLCD_CFG_BURST_MASK (0x3 << SLCD_CFG_BURST_BIT) + #define SLCD_CFG_BURST_4_WORD (0 << SLCD_CFG_BURST_BIT) + #define SLCD_CFG_BURST_8_WORD (1 << SLCD_CFG_BURST_BIT) +#define SLCD_CFG_DWIDTH_BIT 10 +#define SLCD_CFG_DWIDTH_MASK (0x7 << SLCD_CFG_DWIDTH_BIT) + #define SLCD_CFG_DWIDTH_18 (0 << SLCD_CFG_DWIDTH_BIT) + #define SLCD_CFG_DWIDTH_16 (1 << SLCD_CFG_DWIDTH_BIT) + #define SLCD_CFG_DWIDTH_8_x3 (2 << SLCD_CFG_DWIDTH_BIT) + #define SLCD_CFG_DWIDTH_8_x2 (3 << SLCD_CFG_DWIDTH_BIT) + #define SLCD_CFG_DWIDTH_8_x1 (4 << SLCD_CFG_DWIDTH_BIT) + #define SLCD_CFG_DWIDTH_9_x2 (7 << SLCD_CFG_DWIDTH_BIT) +#define SLCD_CFG_CWIDTH_BIT 8 +#define SLCD_CFG_CWIDTH_MASK (0x3 << SLCD_CFG_CWIDTH_BIT) + #define SLCD_CFG_CWIDTH_16BIT (0 << SLCD_CFG_CWIDTH_BIT) + #define SLCD_CFG_CWIDTH_8BIT (1 << SLCD_CFG_CWIDTH_BIT) + #define SLCD_CFG_CWIDTH_18BIT (2 << SLCD_CFG_CWIDTH_BIT) +#define SLCD_CFG_CS_ACTIVE_LOW (0 << 4) +#define SLCD_CFG_CS_ACTIVE_HIGH (1 << 4) +#define SLCD_CFG_RS_CMD_LOW (0 << 3) +#define SLCD_CFG_RS_CMD_HIGH (1 << 3) +#define SLCD_CFG_CLK_ACTIVE_FALLING (0 << 1) +#define SLCD_CFG_CLK_ACTIVE_RISING (1 << 1) +#define SLCD_CFG_TYPE_PARALLEL (0 << 0) +#define SLCD_CFG_TYPE_SERIAL (1 << 0) + +/* SLCD Control Register */ +#define SLCD_CTRL_DMA_EN (1 << 0) + +/* SLCD Status Register */ +#define SLCD_STATE_BUSY (1 << 0) + +/* SLCD Data Register */ +#define SLCD_DATA_RS_DATA (0 << 31) +#define SLCD_DATA_RS_COMMAND (1 << 31) + +/* SLCD FIFO Register */ +#define SLCD_FIFO_RS_DATA (0 << 31) +#define SLCD_FIFO_RS_COMMAND (1 << 31) + + +/************************************************************************* + * LCD (LCD Controller) + *************************************************************************/ +#define LCD_CFG (LCD_BASE + 0x00) /* LCD Configure Register */ +#define LCD_VSYNC (LCD_BASE + 0x04) /* Vertical Synchronize Register */ +#define LCD_HSYNC (LCD_BASE + 0x08) /* Horizontal Synchronize Register */ +#define LCD_VAT (LCD_BASE + 0x0c) /* Virtual Area Setting Register */ +#define LCD_DAH (LCD_BASE + 0x10) /* Display Area Horizontal Start/End Point */ +#define LCD_DAV (LCD_BASE + 0x14) /* Display Area Vertical Start/End Point */ +#define LCD_PS (LCD_BASE + 0x18) /* PS Signal Setting */ +#define LCD_CLS (LCD_BASE + 0x1c) /* CLS Signal Setting */ +#define LCD_SPL (LCD_BASE + 0x20) /* SPL Signal Setting */ +#define LCD_REV (LCD_BASE + 0x24) /* REV Signal Setting */ +#define LCD_CTRL (LCD_BASE + 0x30) /* LCD Control Register */ +#define LCD_STATE (LCD_BASE + 0x34) /* LCD Status Register */ +#define LCD_IID (LCD_BASE + 0x38) /* Interrupt ID Register */ +#define LCD_DA0 (LCD_BASE + 0x40) /* Descriptor Address Register 0 */ +#define LCD_SA0 (LCD_BASE + 0x44) /* Source Address Register 0 */ +#define LCD_FID0 (LCD_BASE + 0x48) /* Frame ID Register 0 */ +#define LCD_CMD0 (LCD_BASE + 0x4c) /* DMA Command Register 0 */ +#define LCD_DA1 (LCD_BASE + 0x50) /* Descriptor Address Register 1 */ +#define LCD_SA1 (LCD_BASE + 0x54) /* Source Address Register 1 */ +#define LCD_FID1 (LCD_BASE + 0x58) /* Frame ID Register 1 */ +#define LCD_CMD1 (LCD_BASE + 0x5c) /* DMA Command Register 1 */ + +#define REG_LCD_CFG REG32(LCD_CFG) +#define REG_LCD_VSYNC REG32(LCD_VSYNC) +#define REG_LCD_HSYNC REG32(LCD_HSYNC) +#define REG_LCD_VAT REG32(LCD_VAT) +#define REG_LCD_DAH REG32(LCD_DAH) +#define REG_LCD_DAV REG32(LCD_DAV) +#define REG_LCD_PS REG32(LCD_PS) +#define REG_LCD_CLS REG32(LCD_CLS) +#define REG_LCD_SPL REG32(LCD_SPL) +#define REG_LCD_REV REG32(LCD_REV) +#define REG_LCD_CTRL REG32(LCD_CTRL) +#define REG_LCD_STATE REG32(LCD_STATE) +#define REG_LCD_IID REG32(LCD_IID) +#define REG_LCD_DA0 REG32(LCD_DA0) +#define REG_LCD_SA0 REG32(LCD_SA0) +#define REG_LCD_FID0 REG32(LCD_FID0) +#define REG_LCD_CMD0 REG32(LCD_CMD0) +#define REG_LCD_DA1 REG32(LCD_DA1) +#define REG_LCD_SA1 REG32(LCD_SA1) +#define REG_LCD_FID1 REG32(LCD_FID1) +#define REG_LCD_CMD1 REG32(LCD_CMD1) + +/* LCD Configure Register */ +#define LCD_CFG_LCDPIN_BIT 31 /* LCD pins selection */ +#define LCD_CFG_LCDPIN_MASK (0x1 << LCD_CFG_LCDPIN_BIT) + #define LCD_CFG_LCDPIN_LCD (0x0 << LCD_CFG_LCDPIN_BIT) + #define LCD_CFG_LCDPIN_SLCD (0x1 << LCD_CFG_LCDPIN_BIT) +#define LCD_CFG_PSM (1 << 23) /* PS signal mode */ +#define LCD_CFG_CLSM (1 << 22) /* CLS signal mode */ +#define LCD_CFG_SPLM (1 << 21) /* SPL signal mode */ +#define LCD_CFG_REVM (1 << 20) /* REV signal mode */ +#define LCD_CFG_HSYNM (1 << 19) /* HSYNC signal mode */ +#define LCD_CFG_PCLKM (1 << 18) /* PCLK signal mode */ +#define LCD_CFG_INVDAT (1 << 17) /* Inverse output data */ +#define LCD_CFG_SYNDIR_IN (1 << 16) /* VSYNC&HSYNC direction */ +#define LCD_CFG_PSP (1 << 15) /* PS pin reset state */ +#define LCD_CFG_CLSP (1 << 14) /* CLS pin reset state */ +#define LCD_CFG_SPLP (1 << 13) /* SPL pin reset state */ +#define LCD_CFG_REVP (1 << 12) /* REV pin reset state */ +#define LCD_CFG_HSP (1 << 11) /* HSYNC pority:0-active high,1-active low */ +#define LCD_CFG_PCP (1 << 10) /* PCLK pority:0-rising,1-falling */ +#define LCD_CFG_DEP (1 << 9) /* DE pority:0-active high,1-active low */ +#define LCD_CFG_VSP (1 << 8) /* VSYNC pority:0-rising,1-falling */ +#define LCD_CFG_PDW_BIT 4 /* STN pins utilization */ +#define LCD_CFG_PDW_MASK (0x3 << LCD_DEV_PDW_BIT) +#define LCD_CFG_PDW_1 (0 << LCD_CFG_PDW_BIT) /* LCD_D[0] */ + #define LCD_CFG_PDW_2 (1 << LCD_CFG_PDW_BIT) /* LCD_D[0:1] */ + #define LCD_CFG_PDW_4 (2 << LCD_CFG_PDW_BIT) /* LCD_D[0:3]/LCD_D[8:11] */ + #define LCD_CFG_PDW_8 (3 << LCD_CFG_PDW_BIT) /* LCD_D[0:7]/LCD_D[8:15] */ +#define LCD_CFG_MODE_BIT 0 /* Display Device Mode Select */ +#define LCD_CFG_MODE_MASK (0x0f << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_GENERIC_TFT (0 << LCD_CFG_MODE_BIT) /* 16,18 bit TFT */ + #define LCD_CFG_MODE_SPECIAL_TFT_1 (1 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_SPECIAL_TFT_2 (2 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_SPECIAL_TFT_3 (3 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_NONINTER_CCIR656 (4 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_INTER_CCIR656 (5 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_SINGLE_CSTN (8 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_SINGLE_MSTN (9 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_DUAL_CSTN (10 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_DUAL_MSTN (11 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_SERIAL_TFT (12 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_GENERIC_18BIT_TFT (13 << LCD_CFG_MODE_BIT) + /* JZ47XX defines */ + #define LCD_CFG_MODE_SHARP_HR (1 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_CASIO_TFT (2 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_SAMSUNG_ALPHA (3 << LCD_CFG_MODE_BIT) + + + +/* Vertical Synchronize Register */ +#define LCD_VSYNC_VPS_BIT 16 /* VSYNC pulse start in line clock, fixed to 0 */ +#define LCD_VSYNC_VPS_MASK (0xffff << LCD_VSYNC_VPS_BIT) +#define LCD_VSYNC_VPE_BIT 0 /* VSYNC pulse end in line clock */ +#define LCD_VSYNC_VPE_MASK (0xffff << LCD_VSYNC_VPS_BIT) + +/* Horizontal Synchronize Register */ +#define LCD_HSYNC_HPS_BIT 16 /* HSYNC pulse start position in dot clock */ +#define LCD_HSYNC_HPS_MASK (0xffff << LCD_HSYNC_HPS_BIT) +#define LCD_HSYNC_HPE_BIT 0 /* HSYNC pulse end position in dot clock */ +#define LCD_HSYNC_HPE_MASK (0xffff << LCD_HSYNC_HPE_BIT) + +/* Virtual Area Setting Register */ +#define LCD_VAT_HT_BIT 16 /* Horizontal Total size in dot clock */ +#define LCD_VAT_HT_MASK (0xffff << LCD_VAT_HT_BIT) +#define LCD_VAT_VT_BIT 0 /* Vertical Total size in dot clock */ +#define LCD_VAT_VT_MASK (0xffff << LCD_VAT_VT_BIT) + +/* Display Area Horizontal Start/End Point Register */ +#define LCD_DAH_HDS_BIT 16 /* Horizontal display area start in dot clock */ +#define LCD_DAH_HDS_MASK (0xffff << LCD_DAH_HDS_BIT) +#define LCD_DAH_HDE_BIT 0 /* Horizontal display area end in dot clock */ +#define LCD_DAH_HDE_MASK (0xffff << LCD_DAH_HDE_BIT) + +/* Display Area Vertical Start/End Point Register */ +#define LCD_DAV_VDS_BIT 16 /* Vertical display area start in line clock */ +#define LCD_DAV_VDS_MASK (0xffff << LCD_DAV_VDS_BIT) +#define LCD_DAV_VDE_BIT 0 /* Vertical display area end in line clock */ +#define LCD_DAV_VDE_MASK (0xffff << LCD_DAV_VDE_BIT) + +/* PS Signal Setting */ +#define LCD_PS_PSS_BIT 16 /* PS signal start position in dot clock */ +#define LCD_PS_PSS_MASK (0xffff << LCD_PS_PSS_BIT) +#define LCD_PS_PSE_BIT 0 /* PS signal end position in dot clock */ +#define LCD_PS_PSE_MASK (0xffff << LCD_PS_PSE_BIT) + +/* CLS Signal Setting */ +#define LCD_CLS_CLSS_BIT 16 /* CLS signal start position in dot clock */ +#define LCD_CLS_CLSS_MASK (0xffff << LCD_CLS_CLSS_BIT) +#define LCD_CLS_CLSE_BIT 0 /* CLS signal end position in dot clock */ +#define LCD_CLS_CLSE_MASK (0xffff << LCD_CLS_CLSE_BIT) + +/* SPL Signal Setting */ +#define LCD_SPL_SPLS_BIT 16 /* SPL signal start position in dot clock */ +#define LCD_SPL_SPLS_MASK (0xffff << LCD_SPL_SPLS_BIT) +#define LCD_SPL_SPLE_BIT 0 /* SPL signal end position in dot clock */ +#define LCD_SPL_SPLE_MASK (0xffff << LCD_SPL_SPLE_BIT) + +/* REV Signal Setting */ +#define LCD_REV_REVS_BIT 16 /* REV signal start position in dot clock */ +#define LCD_REV_REVS_MASK (0xffff << LCD_REV_REVS_BIT) + +/* LCD Control Register */ +#define LCD_CTRL_BST_BIT 28 /* Burst Length Selection */ +#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT) + #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) /* 4-word */ + #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) /* 8-word */ + #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) /* 16-word */ +#define LCD_CTRL_RGB565 (0 << 27) /* RGB565 mode */ +#define LCD_CTRL_RGB555 (1 << 27) /* RGB555 mode */ +#define LCD_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */ +#define LCD_CTRL_FRC_BIT 24 /* STN FRC Algorithm Selection */ +#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT) + #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) /* 16 grayscale */ + #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) /* 4 grayscale */ + #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) /* 2 grayscale */ +#define LCD_CTRL_PDD_BIT 16 /* Load Palette Delay Counter */ +#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT) +#define LCD_CTRL_EOFM (1 << 13) /* EOF interrupt mask */ +#define LCD_CTRL_SOFM (1 << 12) /* SOF interrupt mask */ +#define LCD_CTRL_OFUM (1 << 11) /* Output FIFO underrun interrupt mask */ +#define LCD_CTRL_IFUM0 (1 << 10) /* Input FIFO 0 underrun interrupt mask */ +#define LCD_CTRL_IFUM1 (1 << 9) /* Input FIFO 1 underrun interrupt mask */ +#define LCD_CTRL_LDDM (1 << 8) /* LCD disable done interrupt mask */ +#define LCD_CTRL_QDM (1 << 7) /* LCD quick disable done interrupt mask */ +#define LCD_CTRL_BEDN (1 << 6) /* Endian selection */ +#define LCD_CTRL_PEDN (1 << 5) /* Endian in byte:0-msb first, 1-lsb first */ +#define LCD_CTRL_DIS (1 << 4) /* Disable indicate bit */ +#define LCD_CTRL_ENA (1 << 3) /* LCD enable bit */ +#define LCD_CTRL_BPP_BIT 0 /* Bits Per Pixel */ +#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT) + #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) /* 1 bpp */ + #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) /* 2 bpp */ + #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) /* 4 bpp */ + #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) /* 8 bpp */ + #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) /* 15/16 bpp */ + #define LCD_CTRL_BPP_18_24 (5 << LCD_CTRL_BPP_BIT) /* 18/24/32 bpp */ + +/* LCD Status Register */ +#define LCD_STATE_QD (1 << 7) /* Quick Disable Done */ +#define LCD_STATE_EOF (1 << 5) /* EOF Flag */ +#define LCD_STATE_SOF (1 << 4) /* SOF Flag */ +#define LCD_STATE_OFU (1 << 3) /* Output FIFO Underrun */ +#define LCD_STATE_IFU0 (1 << 2) /* Input FIFO 0 Underrun */ +#define LCD_STATE_IFU1 (1 << 1) /* Input FIFO 1 Underrun */ +#define LCD_STATE_LDD (1 << 0) /* LCD Disabled */ + +/* DMA Command Register */ +#define LCD_CMD_SOFINT (1 << 31) +#define LCD_CMD_EOFINT (1 << 30) +#define LCD_CMD_PAL (1 << 28) +#define LCD_CMD_LEN_BIT 0 +#define LCD_CMD_LEN_MASK (0xffffff << LCD_CMD_LEN_BIT) + + +/************************************************************************* + * USB Device + *************************************************************************/ +#define USB_BASE UDC_BASE + +#define USB_REG_FADDR (USB_BASE + 0x00) /* Function Address 8-bit */ +#define USB_REG_POWER (USB_BASE + 0x01) /* Power Managemetn 8-bit */ +#define USB_REG_INTRIN (USB_BASE + 0x02) /* Interrupt IN 16-bit */ +#define USB_REG_INTROUT (USB_BASE + 0x04) /* Interrupt OUT 16-bit */ +#define USB_REG_INTRINE (USB_BASE + 0x06) /* Intr IN enable 16-bit */ +#define USB_REG_INTROUTE (USB_BASE + 0x08) /* Intr OUT enable 16-bit */ +#define USB_REG_INTRUSB (USB_BASE + 0x0a) /* Interrupt USB 8-bit */ +#define USB_REG_INTRUSBE (USB_BASE + 0x0b) /* Interrupt USB Enable 8-bit */ +#define USB_REG_FRAME (USB_BASE + 0x0c) /* Frame number 16-bit */ +#define USB_REG_INDEX (USB_BASE + 0x0e) /* Index register 8-bit */ +#define USB_REG_TESTMODE (USB_BASE + 0x0f) /* USB test mode 8-bit */ + +#define USB_REG_CSR0 (USB_BASE + 0x12) /* EP0 CSR 8-bit */ +#define USB_REG_COUNT0 (USB_BASE + 0x18) /* bytes in EP0 FIFO 16-bit */ +#define USB_REG_INMAXP (USB_BASE + 0x10) /* EP1-2 IN Max Pkt Size 16-bit */ +#define USB_REG_INCSR (USB_BASE + 0x12) /* EP1-2 IN CSR LSB 8/16bit */ +#define USB_REG_INCSRH (USB_BASE + 0x13) /* EP1-2 IN CSR MSB 8-bit */ +#define USB_REG_OUTMAXP (USB_BASE + 0x14) /* EP1 OUT Max Pkt Size 16-bit */ +#define USB_REG_OUTCSR (USB_BASE + 0x16) /* EP1 OUT CSR LSB 8/16bit */ +#define USB_REG_OUTCSRH (USB_BASE + 0x17) /* EP1 OUT CSR MSB 8-bit */ +#define USB_REG_OUTCOUNT (USB_BASE + 0x18) /* bytes in EP0/1 OUT FIFO 16-bit */ + +#define USB_FIFO_EP0 (USB_BASE + 0x20) +#define USB_FIFO_EP1 (USB_BASE + 0x24) +#define USB_FIFO_EP2 (USB_BASE + 0x28) + +#define USB_REG_EPINFO (USB_BASE + 0x78) /* Endpoint information */ +#define USB_REG_RAMINFO (USB_BASE + 0x79) /* RAM information */ + +#define USB_REG_INTR (USB_BASE + 0x200) /* DMA pending interrupts 8-bit */ +#define USB_REG_CNTL1 (USB_BASE + 0x204) /* DMA channel 1 control 32-bit */ +#define USB_REG_ADDR1 (USB_BASE + 0x208) /* DMA channel 1 AHB memory addr 32-bit */ +#define USB_REG_COUNT1 (USB_BASE + 0x20c) /* DMA channel 1 byte count 32-bit */ +#define USB_REG_CNTL2 (USB_BASE + 0x214) /* DMA channel 2 control 32-bit */ +#define USB_REG_ADDR2 (USB_BASE + 0x218) /* DMA channel 2 AHB memory addr 32-bit */ +#define USB_REG_COUNT2 (USB_BASE + 0x21c) /* DMA channel 2 byte count 32-bit */ + +#define REG_USB_REG_FADDR REG8(USB_REG_FADDR) +#define REG_USB_REG_POWER REG8(USB_REG_POWER) +#define REG_USB_REG_INTRIN REG16(USB_REG_INTRIN) +#define REG_USB_REG_INTROUT REG16(USB_REG_INTROUT) +#define REG_USB_REG_INTRINE REG16(USB_REG_INTRINE) +#define REG_USB_REG_INTROUTE REG16(USB_REG_INTROUTE) +#define REG_USB_REG_INTRUSB REG8(USB_REG_INTRUSB) +#define REG_USB_REG_INTRUSBE REG8(USB_REG_INTRUSBE) +#define REG_USB_REG_FRAME REG16(USB_REG_FRAME) +#define REG_USB_REG_INDEX REG8(USB_REG_INDEX) +#define REG_USB_REG_TESTMODE REG8(USB_REG_TESTMODE) + +#define REG_USB_REG_CSR0 REG8(USB_REG_CSR0) +#define REG_USB_REG_COUNT0 REG16(USB_REG_COUNT0) +#define REG_USB_REG_INMAXP REG16(USB_REG_INMAXP) +#define REG_USB_REG_INCSR REG16(USB_REG_INCSR) +#define REG_USB_REG_INCSRH REG8(USB_REG_INCSRH) +#define REG_USB_REG_OUTMAXP REG16(USB_REG_OUTMAXP) +#define REG_USB_REG_OUTCSR REG16(USB_REG_OUTCSR) +#define REG_USB_REG_OUTCSRH REG8(USB_REG_OUTCSRH) +#define REG_USB_REG_OUTCOUNT REG16(USB_REG_OUTCOUNT) + +#define REG_USB_FIFO_EP0 REG32(USB_FIFO_EP0) +#define REG_USB_FIFO_EP1 REG32(USB_FIFO_EP1) +#define REG_USB_FIFO_EP2 REG32(USB_FIFO_EP2) + +#define REG_USB_REG_INTR REG8(USB_REG_INTR) +#define REG_USB_REG_CNTL1 REG32(USB_REG_CNTL1) +#define REG_USB_REG_ADDR1 REG32(USB_REG_ADDR1) +#define REG_USB_REG_COUNT1 REG32(USB_REG_COUNT1) +#define REG_USB_REG_CNTL2 REG32(USB_REG_CNTL2) +#define REG_USB_REG_ADDR2 REG32(USB_REG_ADDR2) +#define REG_USB_REG_COUNT2 REG32(USB_REG_COUNT2) + +#define REG_USB_REG_EPINFO REG16(USB_REG_EPINFO) +#define REG_USB_REG_RAMINFO REG8(USB_REG_RAMINFO) + + +/* Power register bit masks */ +#define USB_POWER_SUSPENDM 0x01 +#define USB_POWER_RESUME 0x04 +#define USB_POWER_HSMODE 0x10 +#define USB_POWER_HSENAB 0x20 +#define USB_POWER_SOFTCONN 0x40 + +/* Interrupt register bit masks */ +#define USB_INTR_SUSPEND 0x01 +#define USB_INTR_RESUME 0x02 +#define USB_INTR_RESET 0x04 + +#define USB_INTR_EP0 0x0001 +#define USB_INTR_INEP1 0x0002 +#define USB_INTR_INEP2 0x0004 +#define USB_INTR_OUTEP1 0x0002 +#define USB_INTR_OUTEP2 0x0004 + +#define USB_INTR_EP(n) ((n)==0 ? 1 : ((n)*2)) + +/* CSR0 bit masks */ +#define USB_CSR0_OUTPKTRDY 0x01 +#define USB_CSR0_INPKTRDY 0x02 +#define USB_CSR0_SENTSTALL 0x04 +#define USB_CSR0_DATAEND 0x08 +#define USB_CSR0_SETUPEND 0x10 +#define USB_CSR0_SENDSTALL 0x20 +#define USB_CSR0_SVDOUTPKTRDY 0x40 +#define USB_CSR0_SVDSETUPEND 0x80 + +/* Endpoint CSR register bits */ +#define USB_INCSRH_AUTOSET 0x80 +#define USB_INCSRH_ISO 0x40 +#define USB_INCSRH_MODE 0x20 +#define USB_INCSRH_DMAREQENAB 0x10 +#define USB_INCSRH_FRCDATATOG 0x08 +#define USB_INCSRH_DMAREQMODE 0x04 +#define USB_INCSR_CDT 0x40 +#define USB_INCSR_SENTSTALL 0x20 +#define USB_INCSR_SENDSTALL 0x10 +#define USB_INCSR_FF 0x08 +#define USB_INCSR_UNDERRUN 0x04 +#define USB_INCSR_FFNOTEMPT 0x02 +#define USB_INCSR_INPKTRDY 0x01 +#define USB_OUTCSRH_AUTOCLR 0x80 +#define USB_OUTCSRH_ISO 0x40 +#define USB_OUTCSRH_DMAREQENAB 0x20 +#define USB_OUTCSRH_DNYT 0x10 +#define USB_OUTCSRH_DMAREQMODE 0x08 +#define USB_OUTCSR_CDT 0x80 +#define USB_OUTCSR_SENTSTALL 0x40 +#define USB_OUTCSR_SENDSTALL 0x20 +#define USB_OUTCSR_FF 0x10 +#define USB_OUTCSR_DATAERR 0x08 +#define USB_OUTCSR_OVERRUN 0x04 +#define USB_OUTCSR_FFFULL 0x02 +#define USB_OUTCSR_OUTPKTRDY 0x01 + +/* Testmode register bits */ +#define USB_TEST_SE0NAK 0x01 +#define USB_TEST_J 0x02 +#define USB_TEST_K 0x04 +#define USB_TEST_PACKET 0x08 +#define USB_TEST_FORCE_HS 0x10 +#define USB_TEST_FORCE_FS 0x20 +#define USB_TEST_ALL ( USB_TEST_SE0NAK | USB_TEST_J \ + | USB_TEST_K | USB_TEST_PACKET \ + | USB_TEST_FORCE_HS | USB_TEST_FORCE_FS) + +/* DMA control bits */ +#define USB_CNTL_ENA 0x01 +#define USB_CNTL_DIR_IN 0x02 +#define USB_CNTL_MODE_1 0x04 +#define USB_CNTL_INTR_EN 0x08 +#define USB_CNTL_EP(n) ((n) << 4) +#define USB_CNTL_BURST_0 (0 << 9) +#define USB_CNTL_BURST_4 (1 << 9) +#define USB_CNTL_BURST_8 (2 << 9) +#define USB_CNTL_BURST_16 (3 << 9) + +/* DMA interrupt bits */ +#define USB_INTR_DMA_BULKIN 1 +#define USB_INTR_DMA_BULKOUT 2 + + +//---------------------------------------------------------------------- +// +// Module Operation Definitions +// +//---------------------------------------------------------------------- +#ifndef __ASSEMBLY__ + +/*************************************************************************** + * GPIO + ***************************************************************************/ + +//------------------------------------------------------ +// GPIO Pins Description +// +// PORT 0: +// +// PIN/BIT N FUNC0 FUNC1 +// 0 D0 - +// 1 D1 - +// 2 D2 - +// 3 D3 - +// 4 D4 - +// 5 D5 - +// 6 D6 - +// 7 D7 - +// 8 D8 - +// 9 D9 - +// 10 D10 - +// 11 D11 - +// 12 D12 - +// 13 D13 - +// 14 D14 - +// 15 D15 - +// 16 D16 - +// 17 D17 - +// 18 D18 - +// 19 D19 - +// 20 D20 - +// 21 D21 - +// 22 D22 - +// 23 D23 - +// 24 D24 - +// 25 D25 - +// 26 D26 - +// 27 D27 - +// 28 D28 - +// 29 D29 - +// 30 D30 - +// 31 D31 - +// +//------------------------------------------------------ +// PORT 1: +// +// PIN/BIT N FUNC0 FUNC1 +// 0 A0 - +// 1 A1 - +// 2 A2 - +// 3 A3 - +// 4 A4 - +// 5 A5 - +// 6 A6 - +// 7 A7 - +// 8 A8 - +// 9 A9 - +// 10 A10 - +// 11 A11 - +// 12 A12 - +// 13 A13 - +// 14 A14 - +// 15 A15/CL - +// 16 A16/AL - +// 17 LCD_CLS A21 +// 18 LCD_SPL A22 +// 19 DCS# - +// 20 RAS# - +// 21 CAS# - +// 22 RDWE#/BUFD# - +// 23 CKE - +// 24 CKO - +// 25 CS1# - +// 26 CS2# - +// 27 CS3# - +// 28 CS4# - +// 29 RD# - +// 30 WR# - +// 31 WE0# - +// +// Note: PIN15&16 are CL&AL when connecting to NAND flash. +//------------------------------------------------------ +// PORT 2: +// +// PIN/BIT N FUNC0 FUNC1 +// 0 LCD_D0 - +// 1 LCD_D1 - +// 2 LCD_D2 - +// 3 LCD_D3 - +// 4 LCD_D4 - +// 5 LCD_D5 - +// 6 LCD_D6 - +// 7 LCD_D7 - +// 8 LCD_D8 - +// 9 LCD_D9 - +// 10 LCD_D10 - +// 11 LCD_D11 - +// 12 LCD_D12 - +// 13 LCD_D13 - +// 14 LCD_D14 - +// 15 LCD_D15 - +// 16 LCD_D16 - +// 17 LCD_D17 - +// 18 LCD_PCLK - +// 19 LCD_HSYNC - +// 20 LCD_VSYNC - +// 21 LCD_DE - +// 22 LCD_PS A19 +// 23 LCD_REV A20 +// 24 WE1# - +// 25 WE2# - +// 26 WE3# - +// 27 WAIT# - +// 28 FRE# - +// 29 FWE# - +// 30(NOTE:FRB#) - - +// 31 - - +// +// NOTE(1): PIN30 is used for FRB# when connecting to NAND flash. +//------------------------------------------------------ +// PORT 3: +// +// PIN/BIT N FUNC0 FUNC1 +// 0 CIM_D0 - +// 1 CIM_D1 - +// 2 CIM_D2 - +// 3 CIM_D3 - +// 4 CIM_D4 - +// 5 CIM_D5 - +// 6 CIM_D6 - +// 7 CIM_D7 - +// 8 MSC_CMD - +// 9 MSC_CLK - +// 10 MSC_D0 - +// 11 MSC_D1 - +// 12 MSC_D2 - +// 13 MSC_D3 - +// 14 CIM_MCLK - +// 15 CIM_PCLK - +// 16 CIM_VSYNC - +// 17 CIM_HSYNC - +// 18 SSI_CLK SCLK_RSTN +// 19 SSI_CE0# BIT_CLK(AIC) +// 20 SSI_DT SDATA_OUT(AIC) +// 21 SSI_DR SDATA_IN(AIC) +// 22 SSI_CE1#&GPC SYNC(AIC) +// 23 PWM0 I2C_SDA +// 24 PWM1 I2C_SCK +// 25 PWM2 UART0_TxD +// 26 PWM3 UART0_RxD +// 27 PWM4 A17 +// 28 PWM5 A18 +// 29 - - +// 30 PWM6 UART0_CTS/UART1_RxD +// 31 PWM7 UART0_RTS/UART1_TxD +// +////////////////////////////////////////////////////////// + +/* + * p is the port number (0,1,2,3) + * o is the pin offset (0-31) inside the port + * n is the absolute number of a pin (0-127), regardless of the port + */ + +//------------------------------------------- +// Function Pins Mode + +#define __gpio_as_func0(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXFUNS(p) = (1 << o); \ + REG_GPIO_PXSELC(p) = (1 << o); \ +} while (0) + +#define __gpio_as_func1(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXFUNS(p) = (1 << o); \ + REG_GPIO_PXSELS(p) = (1 << o); \ +} while (0) + +/* + * D0 ~ D31, A0 ~ A16, DCS#, RAS#, CAS#, CKE#, + * RDWE#, CKO#, WE0#, WE1#, WE2#, WE3# + */ +#define __gpio_as_sdram_32bit() \ +do { \ + REG_GPIO_PXFUNS(0) = 0xffffffff; \ + REG_GPIO_PXSELC(0) = 0xffffffff; \ + REG_GPIO_PXPES(0) = 0xffffffff; \ + REG_GPIO_PXFUNS(1) = 0x81f9ffff; \ + REG_GPIO_PXSELC(1) = 0x81f9ffff; \ + REG_GPIO_PXPES(1) = 0x81f9ffff; \ + REG_GPIO_PXFUNS(2) = 0x07000000; \ + REG_GPIO_PXSELC(2) = 0x07000000; \ + REG_GPIO_PXPES(2) = 0x07000000; \ +} while (0) + +//#ifdef JZ4740_PAVO +#ifdef JZ4740_4740 +/* + * D0 ~ D15, A0 ~ A16, DCS#, RAS#, CAS#, CKE#, + * RDWE#, CKO#, WE0#, WE1#, WE2#, WE3# + */ +#define __gpio_as_sdram_16bit() \ +do { \ + REG_GPIO_PXFUNS(0) = 0x0000ffff; \ + REG_GPIO_PXFUNS(0) = 0x0000ffff; \ + REG_GPIO_PXPES(0) = 0x0000ffff; \ + REG_GPIO_PXFUNS(1) = 0x81f9ffff; \ + REG_GPIO_PXSELC(1) = 0x81f9ffff; \ + REG_GPIO_PXPES(1) = 0x81f9ffff; \ + REG_GPIO_PXFUNS(2) = 0x07000000; \ + REG_GPIO_PXSELC(2) = 0x07000000; \ + REG_GPIO_PXPES(2) = 0x07000000; \ +} while (0) + +#endif + +//#ifdef JZ4740_VIRGO +#ifdef JZ4740_4720 +/* + * D0 ~ D15, A0 ~ A16, DCS#, RAS#, CAS#, CKE#, + * RDWE#, CKO#, WE0#, WE1#, WE2#, WE3# + */ +#define __gpio_as_sdram_16bit() \ +do { \ + REG_GPIO_PXFUNS(0) = 0x5442bfaa; \ + REG_GPIO_PXSELC(0) = 0x5442bfaa; \ + REG_GPIO_PXPES(0) = 0x5442bfaa; \ + REG_GPIO_PXFUNS(1) = 0x81f9ffff; \ + REG_GPIO_PXSELC(1) = 0x81f9ffff; \ + REG_GPIO_PXPES(1) = 0x81f9ffff; \ + REG_GPIO_PXFUNS(2) = 0x01000000; \ + REG_GPIO_PXSELC(2) = 0x01000000; \ + REG_GPIO_PXPES(2) = 0x01000000; \ +} while (0) +#endif + + +#ifdef JZ4740_4725 +/* + * D0 ~ D15, A0 ~ A16, DCS#, RAS#, CAS#, CKE#, + * RDWE#, CKO#, WE0#, WE1#, WE2#, WE3# + */ +#define __jz4725__gpio_as_sdram_16bit() \ +do { \ + REG_GPIO_PXFUNS(0) = 0x0000ffff; \ + REG_GPIO_PXSELC(0) = 0x0000ffff; \ + REG_GPIO_PXPES(0) = 0x0000ffff; \ + REG_GPIO_PXFUNS(1) = 0x81f9ffff; \ + REG_GPIO_PXSELC(1) = 0x81f9ffff; \ + REG_GPIO_PXPES(1) = 0x81f9ffff; \ + REG_GPIO_PXFUNS(2) = 0x07000000; \ + REG_GPIO_PXSELC(2) = 0x07000000; \ + REG_GPIO_PXPES(2) = 0x07000000; \ +} while (0) +#endif +/* + * CS1#, CLE, ALE, FRE#, FWE#, FRB#, RDWE#/BUFD# + */ +#define __gpio_as_nand() \ +do { \ + REG_GPIO_PXFUNS(1) = 0x02018000; \ + REG_GPIO_PXSELC(1) = 0x02018000; \ + REG_GPIO_PXPES(1) = 0x02018000; \ + REG_GPIO_PXFUNS(2) = 0x30000000; \ + REG_GPIO_PXSELC(2) = 0x30000000; \ + REG_GPIO_PXPES(2) = 0x30000000; \ + REG_GPIO_PXFUNC(2) = 0x40000000; \ + REG_GPIO_PXSELC(2) = 0x40000000; \ + REG_GPIO_PXDIRC(2) = 0x40000000; \ + REG_GPIO_PXPES(2) = 0x40000000; \ + REG_GPIO_PXFUNS(1) = 0x00400000; \ + REG_GPIO_PXSELC(1) = 0x00400000; \ +} while (0) + +/* + * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D7 + */ +#define __gpio_as_nor_8bit() \ +do { \ + REG_GPIO_PXFUNS(0) = 0x000000ff; \ + REG_GPIO_PXSELC(0) = 0x000000ff; \ + REG_GPIO_PXPES(0) = 0x000000ff; \ + REG_GPIO_PXFUNS(1) = 0x7041ffff; \ + REG_GPIO_PXSELC(1) = 0x7041ffff; \ + REG_GPIO_PXPES(1) = 0x7041ffff; \ + REG_GPIO_PXFUNS(1) = 0x00060000; \ + REG_GPIO_PXSELS(1) = 0x00060000; \ + REG_GPIO_PXPES(1) = 0x00060000; \ + REG_GPIO_PXFUNS(2) = 0x08000000; \ + REG_GPIO_PXSELC(2) = 0x08000000; \ + REG_GPIO_PXPES(2) = 0x08000000; \ + REG_GPIO_PXFUNS(2) = 0x00c00000; \ + REG_GPIO_PXSELS(2) = 0x00c00000; \ + REG_GPIO_PXPES(2) = 0x00c00000; \ + REG_GPIO_PXFUNS(3) = 0x18000000; \ + REG_GPIO_PXSELS(3) = 0x18000000; \ + REG_GPIO_PXPES(3) = 0x18000000; \ +} while (0) + +/* + * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D15 + */ +#define __gpio_as_nor_16bit() \ +do { \ + REG_GPIO_PXFUNS(0) = 0x0000ffff; \ + REG_GPIO_PXSELC(0) = 0x0000ffff; \ + REG_GPIO_PXPES(0) = 0x0000ffff; \ + REG_GPIO_PXFUNS(1) = 0x7041ffff; \ + REG_GPIO_PXSELC(1) = 0x7041ffff; \ + REG_GPIO_PXPES(1) = 0x7041ffff; \ + REG_GPIO_PXFUNS(1) = 0x00060000; \ + REG_GPIO_PXSELS(1) = 0x00060000; \ + REG_GPIO_PXPES(1) = 0x00060000; \ + REG_GPIO_PXFUNS(2) = 0x08000000; \ + REG_GPIO_PXSELC(2) = 0x08000000; \ + REG_GPIO_PXPES(2) = 0x08000000; \ + REG_GPIO_PXFUNS(2) = 0x00c00000; \ + REG_GPIO_PXSELS(2) = 0x00c00000; \ + REG_GPIO_PXPES(2) = 0x00c00000; \ + REG_GPIO_PXFUNS(3) = 0x18000000; \ + REG_GPIO_PXSELS(3) = 0x18000000; \ + REG_GPIO_PXPES(3) = 0x18000000; \ +} while (0) + +/* + * UART0_TxD, UART_RxD0 + */ +#define __gpio_as_uart0() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x06000000; \ + REG_GPIO_PXSELS(3) = 0x06000000; \ + REG_GPIO_PXPES(3) = 0x06000000; \ +} while (0) + +/* + * UART1_TxD, UART1_RxD1 + */ +#define __gpio_as_uart1() \ +do { \ + REG_GPIO_PXFUNS(3) = 0xc0000000; \ + REG_GPIO_PXSELS(3) = 0xc0000000; \ + REG_GPIO_PXPES(3) = 0xc0000000; \ +} while (0) + +/* + * LCD_D0~LCD_D15, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE + */ +#define __gpio_as_lcd_16bit() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x003cffff; \ + REG_GPIO_PXSELC(2) = 0x003cffff; \ + REG_GPIO_PXPES(2) = 0x003cffff; \ +} while (0) + +/* + * LCD_D0~LCD_D17, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE + */ +#define __gpio_as_lcd_18bit() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x003fffff; \ + REG_GPIO_PXSELC(2) = 0x003fffff; \ + REG_GPIO_PXPES(2) = 0x003fffff; \ +} while (0) + + +/* LCD_D0~LCD_D7, SLCD_RS, SLCD_CS */ +#define __gpio_as_slcd_8bit() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x001800ff; \ + REG_GPIO_PXSELC(2) = 0x001800ff; \ +} while (0) + +/* LCD_D0~LCD_D7, SLCD_RS, SLCD_CS */ +#define __gpio_as_slcd_9bit() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x001801ff; \ + REG_GPIO_PXSELC(2) = 0x001801ff; \ +} while (0) + +/* LCD_D0~LCD_D15, SLCD_RS, SLCD_CS */ +#define __gpio_as_slcd_16bit() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x0018ffff; \ + REG_GPIO_PXSELC(2) = 0x0018ffff; \ +} while (0) + +/* LCD_D0~LCD_D17, SLCD_RS, SLCD_CS */ +#define __gpio_as_slcd_18bit() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x001bffff; \ + REG_GPIO_PXSELC(2) = 0x001bffff; \ +} while (0) + +/* + * CIM_D0~CIM_D7, CIM_MCLK, CIM_PCLK, CIM_VSYNC, CIM_HSYNC + */ +#define __gpio_as_cim() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x0003c0ff; \ + REG_GPIO_PXSELC(3) = 0x0003c0ff; \ + REG_GPIO_PXPES(3) = 0x0003c0ff; \ +} while (0) + +/* + * SDATA_OUT, SDATA_IN, BIT_CLK, SYNC, SCLK_RESET + */ +#define __gpio_as_aic() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x007c0000; \ + REG_GPIO_PXSELS(3) = 0x007c0000; \ + REG_GPIO_PXPES(3) = 0x007c0000; \ +} while (0) + +/* + * MSC_CMD, MSC_CLK, MSC_D0 ~ MSC_D3 + */ +#define __gpio_as_msc() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x00003f00; \ + REG_GPIO_PXSELC(3) = 0x00003f00; \ + REG_GPIO_PXPES(3) = 0x00003f00; \ +} while (0) + +/* + * SSI_CS0, SSI_CLK, SSI_DT, SSI_DR + */ +#define __gpio_as_ssi() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x003c0000; \ + REG_GPIO_PXSELC(3) = 0x003c0000; \ + REG_GPIO_PXPES(3) = 0x003c0000; \ +} while (0) + +/* + * I2C_SCK, I2C_SDA + */ +#define __gpio_as_i2c() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x01800000; \ + REG_GPIO_PXSELS(3) = 0x01800000; \ + REG_GPIO_PXPES(3) = 0x01800000; \ +} while (0) + +/* + * PWM0 + */ +#define __gpio_as_pwm0() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x00800000; \ + REG_GPIO_PXSELC(3) = 0x00800000; \ + REG_GPIO_PXPES(3) = 0x00800000; \ +} while (0) + +/* + * PWM1 + */ +#define __gpio_as_pwm1() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x01000000; \ + REG_GPIO_PXSELC(3) = 0x01000000; \ + REG_GPIO_PXPES(3) = 0x01000000; \ +} while (0) + +/* + * PWM2 + */ +#define __gpio_as_pwm2() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x02000000; \ + REG_GPIO_PXSELC(3) = 0x02000000; \ + REG_GPIO_PXPES(3) = 0x02000000; \ +} while (0) + +/* + * PWM3 + */ +#define __gpio_as_pwm3() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x04000000; \ + REG_GPIO_PXSELC(3) = 0x04000000; \ + REG_GPIO_PXPES(3) = 0x04000000; \ +} while (0) + +/* + * PWM4 + */ +#define __gpio_as_pwm4() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x08000000; \ + REG_GPIO_PXSELC(3) = 0x08000000; \ + REG_GPIO_PXPES(3) = 0x08000000; \ +} while (0) + +/* + * PWM5 + */ +#define __gpio_as_pwm5() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x10000000; \ + REG_GPIO_PXSELC(3) = 0x10000000; \ + REG_GPIO_PXPES(3) = 0x10000000; \ +} while (0) + +/* + * PWM6 + */ +#define __gpio_as_pwm6() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x40000000; \ + REG_GPIO_PXSELC(3) = 0x40000000; \ + REG_GPIO_PXPES(3) = 0x40000000; \ +} while (0) + +/* + * PWM7 + */ +#define __gpio_as_pwm7() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x80000000; \ + REG_GPIO_PXSELC(3) = 0x80000000; \ + REG_GPIO_PXPES(3) = 0x80000000; \ +} while (0) + +/* + * n = 0 ~ 7 + */ +#define ___gpio_as_pwm(n) __gpio_as_pwm ## n() +#define __gpio_as_pwm(n) ___gpio_as_pwm(n) + +//------------------------------------------- +// GPIO or Interrupt Mode + +#define __gpio_get_port(p) (REG_GPIO_PXPIN(p)) + +#define __gpio_port_as_output(p, o) \ +do { \ + REG_GPIO_PXFUNC(p) = (1 << (o)); \ + REG_GPIO_PXSELC(p) = (1 << (o)); \ + REG_GPIO_PXDIRS(p) = (1 << (o)); \ +} while (0) + +#define __gpio_port_as_input(p, o) \ +do { \ + REG_GPIO_PXFUNC(p) = (1 << (o)); \ + REG_GPIO_PXSELC(p) = (1 << (o)); \ + REG_GPIO_PXDIRC(p) = (1 << (o)); \ +} while (0) + +#define __gpio_as_output(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + __gpio_port_as_output(p, o); \ +} while (0) + +#define __gpio_as_input(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + __gpio_port_as_input(p, o); \ +} while (0) + +#define __gpio_set_pin(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXDATS(p) = (1 << o); \ +} while (0) + +#define __gpio_clear_pin(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXDATC(p) = (1 << o); \ +} while (0) + +#define __gpio_get_pin(n) \ +({ \ + unsigned int p, o, v; \ + p = (n) / 32; \ + o = (n) % 32; \ + if (__gpio_get_port(p) & (1 << o)) \ + v = 1; \ + else \ + v = 0; \ + v; \ +}) + +#define __gpio_as_irq_high_level(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXIMS(p) = (1 << o); \ + REG_GPIO_PXTRGC(p) = (1 << o); \ + REG_GPIO_PXFUNC(p) = (1 << o); \ + REG_GPIO_PXSELS(p) = (1 << o); \ + REG_GPIO_PXDIRS(p) = (1 << o); \ + REG_GPIO_PXFLGC(p) = (1 << o); \ + REG_GPIO_PXIMC(p) = (1 << o); \ +} while (0) + +#define __gpio_as_irq_low_level(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXIMS(p) = (1 << o); \ + REG_GPIO_PXTRGC(p) = (1 << o); \ + REG_GPIO_PXFUNC(p) = (1 << o); \ + REG_GPIO_PXSELS(p) = (1 << o); \ + REG_GPIO_PXDIRC(p) = (1 << o); \ + REG_GPIO_PXFLGC(p) = (1 << o); \ + REG_GPIO_PXIMC(p) = (1 << o); \ +} while (0) + +#define __gpio_as_irq_rise_edge(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXIMS(p) = (1 << o); \ + REG_GPIO_PXTRGS(p) = (1 << o); \ + REG_GPIO_PXFUNC(p) = (1 << o); \ + REG_GPIO_PXSELS(p) = (1 << o); \ + REG_GPIO_PXDIRS(p) = (1 << o); \ + REG_GPIO_PXFLGC(p) = (1 << o); \ + REG_GPIO_PXIMC(p) = (1 << o); \ +} while (0) + +#define __gpio_as_irq_fall_edge(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXIMS(p) = (1 << o); \ + REG_GPIO_PXTRGS(p) = (1 << o); \ + REG_GPIO_PXFUNC(p) = (1 << o); \ + REG_GPIO_PXSELS(p) = (1 << o); \ + REG_GPIO_PXDIRC(p) = (1 << o); \ + REG_GPIO_PXFLGC(p) = (1 << o); \ + REG_GPIO_PXIMC(p) = (1 << o); \ +} while (0) + +#define __gpio_mask_irq(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXIMS(p) = (1 << o); \ +} while (0) + +#define __gpio_unmask_irq(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXIMC(p) = (1 << o); \ +} while (0) + +#define __gpio_ack_irq(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXFLGC(p) = (1 << o); \ +} while (0) + +#define __gpio_get_irq() \ +({ \ + unsigned int p, i, tmp, v = 0; \ + for (p = 3; p >= 0; p--) { \ + tmp = REG_GPIO_PXFLG(p); \ + for (i = 0; i < 32; i++) \ + if (tmp & (1 << i)) \ + v = (32*p + i); \ + } \ + v; \ +}) + +#define __gpio_group_irq(n) \ +({ \ + register int tmp, i; \ + tmp = REG_GPIO_PXFLG((n)); \ + for (i=31;i>=0;i--) \ + if (tmp & (1 << i)) \ + break; \ + i; \ +}) + +#define __gpio_enable_pull(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXPEC(p) = (1 << o); \ +} while (0) + +#define __gpio_disable_pull(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXPES(p) = (1 << o); \ +} while (0) + + +/*************************************************************************** + * CPM + ***************************************************************************/ +#define __cpm_get_pllm() \ + ((REG_CPM_CPPCR & CPM_CPPCR_PLLM_MASK) >> CPM_CPPCR_PLLM_BIT) +#define __cpm_get_plln() \ + ((REG_CPM_CPPCR & CPM_CPPCR_PLLN_MASK) >> CPM_CPPCR_PLLN_BIT) +#define __cpm_get_pllod() \ + ((REG_CPM_CPPCR & CPM_CPPCR_PLLOD_MASK) >> CPM_CPPCR_PLLOD_BIT) + +#define __cpm_get_cdiv() \ + ((REG_CPM_CPCCR & CPM_CPCCR_CDIV_MASK) >> CPM_CPCCR_CDIV_BIT) +#define __cpm_get_hdiv() \ + ((REG_CPM_CPCCR & CPM_CPCCR_HDIV_MASK) >> CPM_CPCCR_HDIV_BIT) +#define __cpm_get_pdiv() \ + ((REG_CPM_CPCCR & CPM_CPCCR_PDIV_MASK) >> CPM_CPCCR_PDIV_BIT) +#define __cpm_get_mdiv() \ + ((REG_CPM_CPCCR & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT) +#define __cpm_get_ldiv() \ + ((REG_CPM_CPCCR & CPM_CPCCR_LDIV_MASK) >> CPM_CPCCR_LDIV_BIT) +#define __cpm_get_udiv() \ + ((REG_CPM_CPCCR & CPM_CPCCR_UDIV_MASK) >> CPM_CPCCR_UDIV_BIT) +#define __cpm_get_i2sdiv() \ + ((REG_CPM_I2SCDR & CPM_I2SCDR_I2SDIV_MASK) >> CPM_I2SCDR_I2SDIV_BIT) +#define __cpm_get_pixdiv() \ + ((REG_CPM_LPCDR & CPM_LPCDR_PIXDIV_MASK) >> CPM_LPCDR_PIXDIV_BIT) +#define __cpm_get_mscdiv() \ + ((REG_CPM_MSCCDR & CPM_MSCCDR_MSCDIV_MASK) >> CPM_MSCCDR_MSCDIV_BIT) + +#define __cpm_set_cdiv(v) \ + (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_CDIV_MASK) | ((v) << (CPM_CPCCR_CDIV_BIT))) +#define __cpm_set_hdiv(v) \ + (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_HDIV_MASK) | ((v) << (CPM_CPCCR_HDIV_BIT))) +#define __cpm_set_pdiv(v) \ + (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_PDIV_MASK) | ((v) << (CPM_CPCCR_PDIV_BIT))) +#define __cpm_set_mdiv(v) \ + (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_MDIV_MASK) | ((v) << (CPM_CPCCR_MDIV_BIT))) +#define __cpm_set_ldiv(v) \ + (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_LDIV_MASK) | ((v) << (CPM_CPCCR_LDIV_BIT))) +#define __cpm_set_udiv(v) \ + (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_UDIV_MASK) | ((v) << (CPM_CPCCR_UDIV_BIT))) +#define __cpm_set_i2sdiv(v) \ + (REG_CPM_I2SCDR = (REG_CPM_I2SCDR & ~CPM_I2SCDR_I2SDIV_MASK) | ((v) << (CPM_I2SCDR_I2SDIV_BIT))) +#define __cpm_set_pixdiv(v) \ + (REG_CPM_LPCDR = (REG_CPM_LPCDR & ~CPM_LPCDR_PIXDIV_MASK) | ((v) << (CPM_LPCDR_PIXDIV_BIT))) +#define __cpm_set_mscdiv(v) \ + (REG_CPM_MSCCDR = (REG_CPM_MSCCDR & ~CPM_MSCCDR_MSCDIV_MASK) | ((v) << (CPM_MSCCDR_MSCDIV_BIT))) + +#define __cpm_select_i2sclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_I2CS) +#define __cpm_select_i2sclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_I2CS) +#define __cpm_enable_cko() (REG_CPM_CPCCR |= CPM_CPCCR_CLKOEN) +#define __cpm_select_usbclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_UCS) +#define __cpm_select_usbclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_UCS) +#define __cpm_enable_pll_change() (REG_CPM_CPCCR |= CPM_CPCCR_CE) +#define __cpm_pllout_direct() (REG_CPM_CPCCR |= CPM_CPCCR_PCS) +#define __cpm_pllout_div2() (REG_CPM_CPCCR &= ~CPM_CPCCR_PCS) + +#define __cpm_pll_is_on() (REG_CPM_CPPCR & CPM_CPPCR_PLLS) +#define __cpm_pll_bypass() (REG_CPM_CPPCR |= CPM_CPPCR_PLLBP) +#define __cpm_pll_enable() (REG_CPM_CPPCR |= CPM_CPPCR_PLLEN) + +#define __cpm_get_cclk_doze_duty() \ + ((REG_CPM_LCR & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT) +#define __cpm_set_cclk_doze_duty(v) \ + (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_DOZE_DUTY_MASK) | ((v) << (CPM_LCR_DOZE_DUTY_BIT))) + +#define __cpm_doze_mode() (REG_CPM_LCR |= CPM_LCR_DOZE_ON) +#define __cpm_idle_mode() \ + (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_IDLE) +#define __cpm_sleep_mode() \ + (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_SLEEP) + +#define __cpm_stop_all() (REG_CPM_CLKGR = 0xffff) +#define __cpm_stop_uart1() (REG_CPM_CLKGR |= CPM_CLKGR_UART1) +#define __cpm_stop_uhc() (REG_CPM_CLKGR |= CPM_CLKGR_UHC) +#define __cpm_stop_ipu() (REG_CPM_CLKGR |= CPM_CLKGR_IPU) +#define __cpm_stop_dmac() (REG_CPM_CLKGR |= CPM_CLKGR_DMAC) +#define __cpm_stop_udc() (REG_CPM_CLKGR |= CPM_CLKGR_UDC) +#define __cpm_stop_lcd() (REG_CPM_CLKGR |= CPM_CLKGR_LCD) +#define __cpm_stop_cim() (REG_CPM_CLKGR |= CPM_CLKGR_CIM) +#define __cpm_stop_sadc() (REG_CPM_CLKGR |= CPM_CLKGR_SADC) +#define __cpm_stop_msc() (REG_CPM_CLKGR |= CPM_CLKGR_MSC) +#define __cpm_stop_aic1() (REG_CPM_CLKGR |= CPM_CLKGR_AIC1) +#define __cpm_stop_aic2() (REG_CPM_CLKGR |= CPM_CLKGR_AIC2) +#define __cpm_stop_ssi() (REG_CPM_CLKGR |= CPM_CLKGR_SSI) +#define __cpm_stop_i2c() (REG_CPM_CLKGR |= CPM_CLKGR_I2C) +#define __cpm_stop_rtc() (REG_CPM_CLKGR |= CPM_CLKGR_RTC) +#define __cpm_stop_tcu() (REG_CPM_CLKGR |= CPM_CLKGR_TCU) +#define __cpm_stop_uart0() (REG_CPM_CLKGR |= CPM_CLKGR_UART0) + +#define __cpm_start_all() (REG_CPM_CLKGR = 0x0) +#define __cpm_start_uart1() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART1) +#define __cpm_start_uhc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UHC) +#define __cpm_start_ipu() (REG_CPM_CLKGR &= ~CPM_CLKGR_IPU) +#define __cpm_start_dmac() (REG_CPM_CLKGR &= ~CPM_CLKGR_DMAC) +#define __cpm_start_udc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UDC) +#define __cpm_start_lcd() (REG_CPM_CLKGR &= ~CPM_CLKGR_LCD) +#define __cpm_start_cim() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIM) +#define __cpm_start_sadc() (REG_CPM_CLKGR &= ~CPM_CLKGR_SADC) +#define __cpm_start_msc() (REG_CPM_CLKGR &= ~CPM_CLKGR_MSC) +#define __cpm_start_aic1() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC1) +#define __cpm_start_aic2() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC2) +#define __cpm_start_ssi() (REG_CPM_CLKGR &= ~CPM_CLKGR_SSI) +#define __cpm_start_i2c() (REG_CPM_CLKGR &= ~CPM_CLKGR_I2C) +#define __cpm_start_rtc() (REG_CPM_CLKGR &= ~CPM_CLKGR_RTC) +#define __cpm_start_tcu() (REG_CPM_CLKGR &= ~CPM_CLKGR_TCU) +#define __cpm_start_uart0() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART0) + +#define __cpm_get_o1st() \ + ((REG_CPM_SCR & CPM_SCR_O1ST_MASK) >> CPM_SCR_O1ST_BIT) +#define __cpm_set_o1st(v) \ + (REG_CPM_SCR = (REG_CPM_SCR & ~CPM_SCR_O1ST_MASK) | ((v) << (CPM_SCR_O1ST_BIT))) +#define __cpm_suspend_usbphy() (REG_CPM_SCR |= CPM_SCR_USBPHY_SUSPEND) +#define __cpm_suspend_usbhost() (REG_CPM_SCR |= CPM_SCR_USBHOST_SUSPEND) +#define __cpm_enable_osc_in_sleep() (REG_CPM_SCR |= CPM_SCR_OSC_ENABLE) + +#ifdef CFG_EXTAL +#define JZ_EXTAL CFG_EXTAL +#else +#define JZ_EXTAL 3686400 +#warning Default EXTCLK is used! +#endif +#define JZ_EXTAL2 32768 /* RTC clock */ + +/* PLL output frequency */ +static __inline__ unsigned int __cpm_get_pllout(void) +{ + unsigned long m, n, no, pllout; + unsigned long cppcr = REG_CPM_CPPCR; + unsigned long od[4] = {1, 2, 2, 4}; + + if ((cppcr & CPM_CPPCR_PLLEN) && !(cppcr & CPM_CPPCR_PLLBP)) + { + m = __cpm_get_pllm() + 2; + n = __cpm_get_plln() + 2; + no = od[__cpm_get_pllod()]; + pllout = ((JZ_EXTAL) / (n * no)) * m; + } + else + pllout = JZ_EXTAL; + + return pllout; +} + +/* PLL output frequency for MSC/I2S/LCD/USB */ +static __inline__ unsigned int __cpm_get_pllout2(void) +{ + if (REG_CPM_CPCCR & CPM_CPCCR_PCS) + return __cpm_get_pllout(); + else + return __cpm_get_pllout()/2; +} + +/* CPU core clock */ +static __inline__ unsigned int __cpm_get_cclk(void) +{ + int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + + return __cpm_get_pllout() / div[__cpm_get_cdiv()]; +} + +/* AHB system bus clock */ +static __inline__ unsigned int __cpm_get_hclk(void) +{ + int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + + return __cpm_get_pllout() / div[__cpm_get_hdiv()]; +} + +/* Memory bus clock */ +static __inline__ unsigned int __cpm_get_mclk(void) +{ + int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + + return __cpm_get_pllout() / div[__cpm_get_mdiv()]; +} + +/* APB peripheral bus clock */ +static __inline__ unsigned int __cpm_get_pclk(void) +{ + int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + + return __cpm_get_pllout() / div[__cpm_get_pdiv()]; +} + +/* LCDC module clock */ +static __inline__ unsigned int __cpm_get_lcdclk(void) +{ + return __cpm_get_pllout2() / (__cpm_get_ldiv() + 1); +} + +/* LCD pixel clock */ +static __inline__ unsigned int __cpm_get_pixclk(void) +{ + return __cpm_get_pllout2() / (__cpm_get_pixdiv() + 1); +} + +/* I2S clock */ +static __inline__ unsigned int __cpm_get_i2sclk(void) +{ + if (REG_CPM_CPCCR & CPM_CPCCR_I2CS) + return __cpm_get_pllout2() / (__cpm_get_i2sdiv() + 1); + else + return JZ_EXTAL; +} + +/* USB clock */ +static __inline__ unsigned int __cpm_get_usbclk(void) +{ + if (REG_CPM_CPCCR & CPM_CPCCR_UCS) + return __cpm_get_pllout2() / (__cpm_get_udiv() + 1); + else + return JZ_EXTAL; +} + +/* MSC clock */ +static __inline__ unsigned int __cpm_get_mscclk(void) +{ + return __cpm_get_pllout2() / (__cpm_get_mscdiv() + 1); +} + +/* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */ +static __inline__ unsigned int __cpm_get_extalclk(void) +{ + return JZ_EXTAL; +} + +/* RTC clock for CPM,INTC,RTC,TCU,WDT */ +static __inline__ unsigned int __cpm_get_rtcclk(void) +{ + return JZ_EXTAL2; +} + +/* + * Output 24MHz for SD and 16MHz for MMC. + */ +static __inline__ void __cpm_select_msc_clk(int sd) +{ + unsigned int pllout2 = __cpm_get_pllout2(); + unsigned int div = 0; + + if (sd) + div = pllout2 / 24000000; + else + div = pllout2 / 16000000; + + REG_CPM_MSCCDR = div - 1; +} + +/* + * Output 48MHz for SD and 16MHz for MMC. + */ +static __inline__ void __cpm_select_msc_hs_clk(int sd) +{ + unsigned int pllout2 = __cpm_get_pllout2(); + unsigned int div = 0; + + if (sd) + div = pllout2 / 48000000; + else + div = pllout2 / 16000000; + + REG_CPM_MSCCDR = div - 1; +} + +/*************************************************************************** + * TCU + ***************************************************************************/ +// where 'n' is the TCU channel +#define __tcu_select_extalclk(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_EXT_EN) +#define __tcu_select_rtcclk(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_RTC_EN) +#define __tcu_select_pclk(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_PCK_EN) + +#define __tcu_select_clk_div1(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1) +#define __tcu_select_clk_div4(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE4) +#define __tcu_select_clk_div16(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE16) +#define __tcu_select_clk_div64(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE64) +#define __tcu_select_clk_div256(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE256) +#define __tcu_select_clk_div1024(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1024) + +#define __tcu_enable_pwm_output(n) ( REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_EN ) +#define __tcu_disable_pwm_output(n) ( REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_EN ) + +#define __tcu_init_pwm_output_high(n) ( REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_INITL_HIGH ) +#define __tcu_init_pwm_output_low(n) ( REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_INITL_HIGH ) + +#define __tcu_set_pwm_output_shutdown_graceful(n) ( REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_SD ) +#define __tcu_set_pwm_output_shutdown_abrupt(n) ( REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_SD ) + +#define __tcu_start_counter(n) ( REG_TCU_TESR |= (1 << (n)) ) +#define __tcu_stop_counter(n) ( REG_TCU_TECR |= (1 << (n)) ) + +#define __tcu_half_match_flag(n) ( REG_TCU_TFR & (1 << ((n) + 16)) ) +#define __tcu_full_match_flag(n) ( REG_TCU_TFR & (1 << (n)) ) +#define __tcu_set_half_match_flag(n) ( REG_TCU_TFSR = (1 << ((n) + 16)) ) +#define __tcu_set_full_match_flag(n) ( REG_TCU_TFSR = (1 << (n)) ) +#define __tcu_clear_half_match_flag(n) ( REG_TCU_TFCR = (1 << ((n) + 16)) ) +#define __tcu_clear_full_match_flag(n) ( REG_TCU_TFCR = (1 << (n)) ) +#define __tcu_mask_half_match_irq(n) ( REG_TCU_TMSR = (1 << ((n) + 16)) ) +#define __tcu_mask_full_match_irq(n) ( REG_TCU_TMSR = (1 << (n)) ) +#define __tcu_unmask_half_match_irq(n) ( REG_TCU_TMCR = (1 << ((n) + 16)) ) +#define __tcu_unmask_full_match_irq(n) ( REG_TCU_TMCR = (1 << (n)) ) + +#define __tcu_wdt_clock_stopped() ( REG_TCU_TSR & TCU_TSSR_WDTSC ) +#define __tcu_timer_clock_stopped(n) ( REG_TCU_TSR & (1 << (n)) ) + +#define __tcu_start_wdt_clock() ( REG_TCU_TSCR = TCU_TSSR_WDTSC ) +#define __tcu_start_timer_clock(n) ( REG_TCU_TSCR = (1 << (n)) ) + +#define __tcu_stop_wdt_clock() ( REG_TCU_TSSR = TCU_TSSR_WDTSC ) +#define __tcu_stop_timer_clock(n) ( REG_TCU_TSSR = (1 << (n)) ) + +#define __tcu_get_count(n) ( REG_TCU_TCNT((n)) ) +#define __tcu_set_count(n,v) ( REG_TCU_TCNT((n)) = (v) ) +#define __tcu_set_full_data(n,v) ( REG_TCU_TDFR((n)) = (v) ) +#define __tcu_set_half_data(n,v) ( REG_TCU_TDHR((n)) = (v) ) + + +/*************************************************************************** + * WDT + ***************************************************************************/ +#define __wdt_start() ( REG_WDT_TCER |= WDT_TCER_TCEN ) +#define __wdt_stop() ( REG_WDT_TCER &= ~WDT_TCER_TCEN ) +#define __wdt_set_count(v) ( REG_WDT_TCNT = (v) ) +#define __wdt_set_data(v) ( REG_WDT_TDR = (v) ) + +#define __wdt_select_extalclk() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_EXT_EN) +#define __wdt_select_rtcclk() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_RTC_EN) +#define __wdt_select_pclk() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_PCK_EN) + +#define __wdt_select_clk_div1() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1) +#define __wdt_select_clk_div4() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE4) +#define __wdt_select_clk_div16() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE16) +#define __wdt_select_clk_div64() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE64) +#define __wdt_select_clk_div256() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE256) +#define __wdt_select_clk_div1024() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1024) + + +/*************************************************************************** + * UART + ***************************************************************************/ + +#define __uart_enable() ( REG8(UART0_FCR) |= UARTFCR_UUE | UARTFCR_FE ) +#define __uart_disable() ( REG8(UART0_FCR) = ~UARTFCR_UUE ) + +#define __uart_enable_transmit_irq() ( REG8(UART0_IER) |= UARTIER_TIE ) +#define __uart_disable_transmit_irq() ( REG8(UART0_IER) &= ~UARTIER_TIE ) + +#define __uart_enable_receive_irq() \ + ( REG8(UART0_IER) |= UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE ) +#define __uart_disable_receive_irq() \ + ( REG8(UART0_IER) &= ~(UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE) ) + +#define __uart_enable_loopback() ( REG8(UART0_MCR) |= UARTMCR_LOOP ) +#define __uart_disable_loopback() ( REG8(UART0_MCR) &= ~UARTMCR_LOOP ) + +#define __uart_set_8n1() ( REG8(UART0_LCR) = UARTLCR_WLEN_8 ) + +#define __uart_set_baud(devclk, baud) \ + do { \ + REG8(UART0_LCR) |= UARTLCR_DLAB; \ + REG8(UART0_DLLR) = (devclk / 16 / baud) & 0xff; \ + REG8(UART0_DLHR) = ((devclk / 16 / baud) >> 8) & 0xff; \ + REG8(UART0_LCR) &= ~UARTLCR_DLAB; \ + } while (0) + +#define __uart_parity_error() ( (REG8(UART0_LSR) & UARTLSR_PER) != 0 ) +#define __uart_clear_errors() \ + ( REG8(UART0_LSR) &= ~(UARTLSR_ORER | UARTLSR_BRK | UARTLSR_FER | UARTLSR_PER | UARTLSR_RFER) ) + +#define __uart_transmit_fifo_empty() ( (REG8(UART0_LSR) & UARTLSR_TDRQ) != 0 ) +#define __uart_transmit_end() ( (REG8(UART0_LSR) & UARTLSR_TEMT) != 0 ) +#define __uart_transmit_char(ch) ( REG8(UART0_TDR) = (ch) ) +#define __uart_receive_fifo_full() ( (REG8(UART0_LSR) & UARTLSR_DR) != 0 ) +#define __uart_receive_ready() ( (REG8(UART0_LSR) & UARTLSR_DR) != 0 ) +#define __uart_receive_char() REG8(UART0_RDR) +#define __uart_disable_irda() ( REG8(UART0_SIRCR) &= ~(SIRCR_TSIRE | SIRCR_RSIRE) ) +#define __uart_enable_irda() \ + /* Tx high pulse as 0, Rx low pulse as 0 */ \ + ( REG8(UART0_SIRCR) = SIRCR_TSIRE | SIRCR_RSIRE | SIRCR_RXPL | SIRCR_TPWS ) + + +/*************************************************************************** + * DMAC + ***************************************************************************/ + +/* n is the DMA channel (0 - 5) */ + +#define __dmac_enable_module() \ + ( REG_DMAC_DMACR |= DMAC_DMACR_DMAE | DMAC_DMACR_PR_RR ) +#define __dmac_disable_module() \ + ( REG_DMAC_DMACR &= ~DMAC_DMACR_DMAE ) + +/* p=0,1,2,3 */ +#define __dmac_set_priority(p) \ +do { \ + REG_DMAC_DMACR &= ~DMAC_DMACR_PR_MASK; \ + REG_DMAC_DMACR |= ((p) << DMAC_DMACR_PR_BIT); \ +} while (0) + +#define __dmac_test_halt_error() ( REG_DMAC_DMACR & DMAC_DMACR_HLT ) +#define __dmac_test_addr_error() ( REG_DMAC_DMACR & DMAC_DMACR_AR ) + +#define __dmac_enable_descriptor(n) \ + ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_NDES ) +#define __dmac_disable_descriptor(n) \ + ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_NDES ) + +#define __dmac_enable_channel(n) \ + ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_EN ) +#define __dmac_disable_channel(n) \ + ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_EN ) +#define __dmac_channel_enabled(n) \ + ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_EN ) + +#define __dmac_channel_enable_irq(n) \ + ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TIE ) +#define __dmac_channel_disable_irq(n) \ + ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TIE ) + +#define __dmac_channel_transmit_halt_detected(n) \ + ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_HLT ) +#define __dmac_channel_transmit_end_detected(n) \ + ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_TT ) +#define __dmac_channel_address_error_detected(n) \ + ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_AR ) +#define __dmac_channel_count_terminated_detected(n) \ + ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_CT ) +#define __dmac_channel_descriptor_invalid_detected(n) \ + ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_INV ) + +#define __dmac_channel_clear_transmit_halt(n) \ + ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT ) +#define __dmac_channel_clear_transmit_end(n) \ + ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TT ) +#define __dmac_channel_clear_address_error(n) \ + ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR ) +#define __dmac_channel_clear_count_terminated(n) \ + ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_CT ) +#define __dmac_channel_clear_descriptor_invalid(n) \ + ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_INV ) + +#define __dmac_channel_set_single_mode(n) \ + ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TM ) +#define __dmac_channel_set_block_mode(n) \ + ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TM ) + +#define __dmac_channel_set_transfer_unit_32bit(n) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ + REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BIT; \ +} while (0) + +#define __dmac_channel_set_transfer_unit_16bit(n) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ + REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BIT; \ +} while (0) + +#define __dmac_channel_set_transfer_unit_8bit(n) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ + REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_8BIT; \ +} while (0) + +#define __dmac_channel_set_transfer_unit_16byte(n) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ + REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BYTE; \ +} while (0) + +#define __dmac_channel_set_transfer_unit_32byte(n) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ + REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BYTE; \ +} while (0) + +/* w=8,16,32 */ +#define __dmac_channel_set_dest_port_width(n,w) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DWDH_MASK; \ + REG_DMAC_DCMD((n)) |= DMAC_DCMD_DWDH_##w; \ +} while (0) + +/* w=8,16,32 */ +#define __dmac_channel_set_src_port_width(n,w) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SWDH_MASK; \ + REG_DMAC_DCMD((n)) |= DMAC_DCMD_SWDH_##w; \ +} while (0) + +/* v=0-15 */ +#define __dmac_channel_set_rdil(n,v) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_RDIL_MASK; \ + REG_DMAC_DCMD((n)) |= ((v) << DMAC_DCMD_RDIL_BIT); \ +} while (0) + +#define __dmac_channel_dest_addr_fixed(n) \ + ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DAI ) +#define __dmac_channel_dest_addr_increment(n) \ + ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_DAI ) + +#define __dmac_channel_src_addr_fixed(n) \ + ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SAI ) +#define __dmac_channel_src_addr_increment(n) \ + ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_SAI ) + +#define __dmac_channel_set_doorbell(n) \ + ( REG_DMAC_DMADBSR = (1 << (n)) ) + +#define __dmac_channel_irq_detected(n) ( REG_DMAC_DMAIPR & (1 << (n)) ) +#define __dmac_channel_ack_irq(n) ( REG_DMAC_DMAIPR &= ~(1 << (n)) ) + +static __inline__ int __dmac_get_irq(void) +{ + int i; + for (i = 0; i < MAX_DMA_NUM; i++) + if (__dmac_channel_irq_detected(i)) + return i; + return -1; +} + + +/*************************************************************************** + * AIC (AC'97 & I2S Controller) + ***************************************************************************/ + +#define __aic_enable() ( REG_AIC_FR |= AIC_FR_ENB ) +#define __aic_disable() ( REG_AIC_FR &= ~AIC_FR_ENB ) + +#define __aic_select_ac97() ( REG_AIC_FR &= ~AIC_FR_AUSEL ) +#define __aic_select_i2s() ( REG_AIC_FR |= AIC_FR_AUSEL ) + +#define __i2s_as_master() ( REG_AIC_FR |= AIC_FR_BCKD | AIC_FR_SYNCD ) +#define __i2s_as_slave() ( REG_AIC_FR &= ~(AIC_FR_BCKD | AIC_FR_SYNCD) ) +#define __aic_reset_status() ( REG_AIC_FR & AIC_FR_RST ) + +#define __aic_reset() \ +do { \ + REG_AIC_FR |= AIC_FR_RST; \ +} while(0) + + +#define __aic_set_transmit_trigger(n) \ +do { \ + REG_AIC_FR &= ~AIC_FR_TFTH_MASK; \ + REG_AIC_FR |= ((n) << AIC_FR_TFTH_BIT); \ +} while(0) + +#define __aic_set_receive_trigger(n) \ +do { \ + REG_AIC_FR &= ~AIC_FR_RFTH_MASK; \ + REG_AIC_FR |= ((n) << AIC_FR_RFTH_BIT); \ +} while(0) + +#define __aic_enable_record() ( REG_AIC_CR |= AIC_CR_EREC ) +#define __aic_disable_record() ( REG_AIC_CR &= ~AIC_CR_EREC ) +#define __aic_enable_replay() ( REG_AIC_CR |= AIC_CR_ERPL ) +#define __aic_disable_replay() ( REG_AIC_CR &= ~AIC_CR_ERPL ) +#define __aic_enable_loopback() ( REG_AIC_CR |= AIC_CR_ENLBF ) +#define __aic_disable_loopback() ( REG_AIC_CR &= ~AIC_CR_ENLBF ) + +#define __aic_flush_fifo() ( REG_AIC_CR |= AIC_CR_FLUSH ) +#define __aic_unflush_fifo() ( REG_AIC_CR &= ~AIC_CR_FLUSH ) + +#define __aic_enable_transmit_intr() \ + ( REG_AIC_CR |= (AIC_CR_ETFS | AIC_CR_ETUR) ) +#define __aic_disable_transmit_intr() \ + ( REG_AIC_CR &= ~(AIC_CR_ETFS | AIC_CR_ETUR) ) +#define __aic_enable_receive_intr() \ + ( REG_AIC_CR |= (AIC_CR_ERFS | AIC_CR_EROR) ) +#define __aic_disable_receive_intr() \ + ( REG_AIC_CR &= ~(AIC_CR_ERFS | AIC_CR_EROR) ) + +#define __aic_enable_transmit_dma() ( REG_AIC_CR |= AIC_CR_TDMS ) +#define __aic_disable_transmit_dma() ( REG_AIC_CR &= ~AIC_CR_TDMS ) +#define __aic_enable_receive_dma() ( REG_AIC_CR |= AIC_CR_RDMS ) +#define __aic_disable_receive_dma() ( REG_AIC_CR &= ~AIC_CR_RDMS ) + +#define __aic_enable_mono2stereo() ( REG_AIC_CR |= AIC_CR_M2S ) +#define __aic_disable_mono2stereo() ( REG_AIC_CR &= ~AIC_CR_M2S ) +#define __aic_enable_byteswap() ( REG_AIC_CR |= AIC_CR_ENDSW ) +#define __aic_disable_byteswap() ( REG_AIC_CR &= ~AIC_CR_ENDSW ) +#define __aic_enable_unsignadj() ( REG_AIC_CR |= AIC_CR_AVSTSU ) +#define __aic_disable_unsignadj() ( REG_AIC_CR &= ~AIC_CR_AVSTSU ) + +#define AC97_PCM_XS_L_FRONT AIC_ACCR1_XS_SLOT3 +#define AC97_PCM_XS_R_FRONT AIC_ACCR1_XS_SLOT4 +#define AC97_PCM_XS_CENTER AIC_ACCR1_XS_SLOT6 +#define AC97_PCM_XS_L_SURR AIC_ACCR1_XS_SLOT7 +#define AC97_PCM_XS_R_SURR AIC_ACCR1_XS_SLOT8 +#define AC97_PCM_XS_LFE AIC_ACCR1_XS_SLOT9 + +#define AC97_PCM_RS_L_FRONT AIC_ACCR1_RS_SLOT3 +#define AC97_PCM_RS_R_FRONT AIC_ACCR1_RS_SLOT4 +#define AC97_PCM_RS_CENTER AIC_ACCR1_RS_SLOT6 +#define AC97_PCM_RS_L_SURR AIC_ACCR1_RS_SLOT7 +#define AC97_PCM_RS_R_SURR AIC_ACCR1_RS_SLOT8 +#define AC97_PCM_RS_LFE AIC_ACCR1_RS_SLOT9 + +#define __ac97_set_xs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK ) +#define __ac97_set_xs_mono() \ +do { \ + REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ + REG_AIC_ACCR1 |= AC97_PCM_XS_R_FRONT; \ +} while(0) +#define __ac97_set_xs_stereo() \ +do { \ + REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ + REG_AIC_ACCR1 |= AC97_PCM_XS_L_FRONT | AC97_PCM_XS_R_FRONT; \ +} while(0) + +/* In fact, only stereo is support now. */ +#define __ac97_set_rs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK ) +#define __ac97_set_rs_mono() \ +do { \ + REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ + REG_AIC_ACCR1 |= AC97_PCM_RS_R_FRONT; \ +} while(0) +#define __ac97_set_rs_stereo() \ +do { \ + REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ + REG_AIC_ACCR1 |= AC97_PCM_RS_L_FRONT | AC97_PCM_RS_R_FRONT; \ +} while(0) + +#define __ac97_warm_reset_codec() \ + do { \ + REG_AIC_ACCR2 |= AIC_ACCR2_SA; \ + REG_AIC_ACCR2 |= AIC_ACCR2_SS; \ + udelay(2); \ + REG_AIC_ACCR2 &= ~AIC_ACCR2_SS; \ + REG_AIC_ACCR2 &= ~AIC_ACCR2_SA; \ + } while (0) + +#define __ac97_cold_reset_codec() \ + do { \ + REG_AIC_ACCR2 |= AIC_ACCR2_SR; \ + udelay(2); \ + REG_AIC_ACCR2 &= ~AIC_ACCR2_SR; \ + } while (0) + +/* n=8,16,18,20 */ +#define __ac97_set_iass(n) \ + ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_IASS_MASK) | AIC_ACCR2_IASS_##n##BIT ) +#define __ac97_set_oass(n) \ + ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_OASS_MASK) | AIC_ACCR2_OASS_##n##BIT ) + +#define __i2s_select_i2s() ( REG_AIC_I2SCR &= ~AIC_I2SCR_AMSL ) +#define __i2s_select_msbjustified() ( REG_AIC_I2SCR |= AIC_I2SCR_AMSL ) + +/* n=8,16,18,20,24 */ +/*#define __i2s_set_sample_size(n) \ + ( REG_AIC_I2SCR |= (REG_AIC_I2SCR & ~AIC_I2SCR_WL_MASK) | AIC_I2SCR_WL_##n##BIT )*/ + +#define __i2s_set_oss_sample_size(n) \ + ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_OSS_MASK) | AIC_CR_OSS_##n##BIT ) +#define __i2s_set_iss_sample_size(n) \ + ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_ISS_MASK) | AIC_CR_ISS_##n##BIT ) + +#define __i2s_stop_bitclk() ( REG_AIC_I2SCR |= AIC_I2SCR_STPBK ) +#define __i2s_start_bitclk() ( REG_AIC_I2SCR &= ~AIC_I2SCR_STPBK ) + +#define __aic_transmit_request() ( REG_AIC_SR & AIC_SR_TFS ) +#define __aic_receive_request() ( REG_AIC_SR & AIC_SR_RFS ) +#define __aic_transmit_underrun() ( REG_AIC_SR & AIC_SR_TUR ) +#define __aic_receive_overrun() ( REG_AIC_SR & AIC_SR_ROR ) + +#define __aic_clear_errors() ( REG_AIC_SR &= ~(AIC_SR_TUR | AIC_SR_ROR) ) + +#define __aic_get_transmit_resident() \ + ( (REG_AIC_SR & AIC_SR_TFL_MASK) >> AIC_SR_TFL_BIT ) +#define __aic_get_receive_count() \ + ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT ) + +#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT ) +#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR ) +#define __ac97_status_receive_timeout() ( REG_AIC_ACSR & AIC_ACSR_RSTO ) +#define __ac97_codec_is_low_power_mode() ( REG_AIC_ACSR & AIC_ACSR_CLPM ) +#define __ac97_codec_is_ready() ( REG_AIC_ACSR & AIC_ACSR_CRDY ) +#define __ac97_slot_error_detected() ( REG_AIC_ACSR & AIC_ACSR_SLTERR ) +#define __ac97_clear_slot_error() ( REG_AIC_ACSR &= ~AIC_ACSR_SLTERR ) + +#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY ) + +#define CODEC_READ_CMD (1 << 19) +#define CODEC_WRITE_CMD (0 << 19) +#define CODEC_REG_INDEX_BIT 12 +#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */ +#define CODEC_REG_DATA_BIT 4 +#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */ + +#define __ac97_out_rcmd_addr(reg) \ +do { \ + REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ +} while (0) + +#define __ac97_out_wcmd_addr(reg) \ +do { \ + REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ +} while (0) + +#define __ac97_out_data(value) \ +do { \ + REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \ +} while (0) + +#define __ac97_in_data() \ + ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT ) + +#define __ac97_in_status_addr() \ + ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT ) + +#define __i2s_set_sample_rate(i2sclk, sync) \ + ( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) ) + +#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) ) +#define __aic_read_rfifo() ( REG_AIC_DR ) + +#define __aic_internal_codec() ( REG_AIC_FR |= AIC_FR_ICDC ) +#define __aic_external_codec() ( REG_AIC_FR &= ~AIC_FR_ICDC ) + +#define AIC_FR_LSMP (1 << 6) +#define __aic_play_lastsample() ( REG_AIC_FR |= AIC_FR_LSMP ) +// +// Define next ops for AC97 compatible +// + +#define AC97_ACSR AIC_ACSR + +#define __ac97_enable() __aic_enable(); __aic_select_ac97() +#define __ac97_disable() __aic_disable() +#define __ac97_reset() __aic_reset() + +#define __ac97_set_transmit_trigger(n) __aic_set_transmit_trigger(n) +#define __ac97_set_receive_trigger(n) __aic_set_receive_trigger(n) + +#define __ac97_enable_record() __aic_enable_record() +#define __ac97_disable_record() __aic_disable_record() +#define __ac97_enable_replay() __aic_enable_replay() +#define __ac97_disable_replay() __aic_disable_replay() +#define __ac97_enable_loopback() __aic_enable_loopback() +#define __ac97_disable_loopback() __aic_disable_loopback() + +#define __ac97_enable_transmit_dma() __aic_enable_transmit_dma() +#define __ac97_disable_transmit_dma() __aic_disable_transmit_dma() +#define __ac97_enable_receive_dma() __aic_enable_receive_dma() +#define __ac97_disable_receive_dma() __aic_disable_receive_dma() + +#define __ac97_transmit_request() __aic_transmit_request() +#define __ac97_receive_request() __aic_receive_request() +#define __ac97_transmit_underrun() __aic_transmit_underrun() +#define __ac97_receive_overrun() __aic_receive_overrun() + +#define __ac97_clear_errors() __aic_clear_errors() + +#define __ac97_get_transmit_resident() __aic_get_transmit_resident() +#define __ac97_get_receive_count() __aic_get_receive_count() + +#define __ac97_enable_transmit_intr() __aic_enable_transmit_intr() +#define __ac97_disable_transmit_intr() __aic_disable_transmit_intr() +#define __ac97_enable_receive_intr() __aic_enable_receive_intr() +#define __ac97_disable_receive_intr() __aic_disable_receive_intr() + +#define __ac97_write_tfifo(v) __aic_write_tfifo(v) +#define __ac97_read_rfifo() __aic_read_rfifo() + +// +// Define next ops for I2S compatible +// + +#define I2S_ACSR AIC_I2SSR + +#define __i2s_enable() __aic_enable(); __aic_select_i2s() +#define __i2s_disable() __aic_disable() +#define __i2s_reset() __aic_reset() + +#define __i2s_set_transmit_trigger(n) __aic_set_transmit_trigger(n) +#define __i2s_set_receive_trigger(n) __aic_set_receive_trigger(n) + +#define __i2s_enable_record() __aic_enable_record() +#define __i2s_disable_record() __aic_disable_record() +#define __i2s_enable_replay() __aic_enable_replay() +#define __i2s_disable_replay() __aic_disable_replay() +#define __i2s_enable_loopback() __aic_enable_loopback() +#define __i2s_disable_loopback() __aic_disable_loopback() + +#define __i2s_enable_transmit_dma() __aic_enable_transmit_dma() +#define __i2s_disable_transmit_dma() __aic_disable_transmit_dma() +#define __i2s_enable_receive_dma() __aic_enable_receive_dma() +#define __i2s_disable_receive_dma() __aic_disable_receive_dma() + +#define __i2s_transmit_request() __aic_transmit_request() +#define __i2s_receive_request() __aic_receive_request() +#define __i2s_transmit_underrun() __aic_transmit_underrun() +#define __i2s_receive_overrun() __aic_receive_overrun() + +#define __i2s_clear_errors() __aic_clear_errors() + +#define __i2s_get_transmit_resident() __aic_get_transmit_resident() +#define __i2s_get_receive_count() __aic_get_receive_count() + +#define __i2s_enable_transmit_intr() __aic_enable_transmit_intr() +#define __i2s_disable_transmit_intr() __aic_disable_transmit_intr() +#define __i2s_enable_receive_intr() __aic_enable_receive_intr() +#define __i2s_disable_receive_intr() __aic_disable_receive_intr() + +#define __i2s_write_tfifo(v) __aic_write_tfifo(v) +#define __i2s_read_rfifo() __aic_read_rfifo() + +#define __i2s_reset_codec() \ + do { \ + } while (0) + + +/*************************************************************************** + * ICDC + ***************************************************************************/ +#define __i2s_internal_codec() __aic_internal_codec() +#define __i2s_external_codec() __aic_external_codec() + +/*************************************************************************** + * INTC + ***************************************************************************/ +#define __intc_unmask_irq(n) ( REG_INTC_IMCR = (1 << (n)) ) +#define __intc_mask_irq(n) ( REG_INTC_IMSR = (1 << (n)) ) +#define __intc_ack_irq(n) ( REG_INTC_IPR = (1 << (n)) ) + + +/*************************************************************************** + * I2C + ***************************************************************************/ + +#define __i2c_enable() ( REG_I2C_CR |= I2C_CR_I2CE ) +#define __i2c_disable() ( REG_I2C_CR &= ~I2C_CR_I2CE ) + +#define __i2c_send_start() ( REG_I2C_CR |= I2C_CR_STA ) +#define __i2c_send_stop() ( REG_I2C_CR |= I2C_CR_STO ) +#define __i2c_send_ack() ( REG_I2C_CR &= ~I2C_CR_AC ) +#define __i2c_send_nack() ( REG_I2C_CR |= I2C_CR_AC ) + +#define __i2c_set_drf() ( REG_I2C_SR |= I2C_SR_DRF ) +#define __i2c_clear_drf() ( REG_I2C_SR &= ~I2C_SR_DRF ) +#define __i2c_check_drf() ( REG_I2C_SR & I2C_SR_DRF ) + +#define __i2c_received_ack() ( !(REG_I2C_SR & I2C_SR_ACKF) ) +#define __i2c_is_busy() ( REG_I2C_SR & I2C_SR_BUSY ) +#define __i2c_transmit_ended() ( REG_I2C_SR & I2C_SR_TEND ) + +#define __i2c_set_clk(dev_clk, i2c_clk) \ + ( REG_I2C_GR = (dev_clk) / (16*(i2c_clk)) - 1 ) + +#define __i2c_read() ( REG_I2C_DR ) +#define __i2c_write(val) ( REG_I2C_DR = (val) ) + + +/*************************************************************************** + * MSC + ***************************************************************************/ + +#define __msc_start_op() \ + ( REG_MSC_STRPCL = MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START ) + +#define __msc_set_resto(to) ( REG_MSC_RESTO = to ) +#define __msc_set_rdto(to) ( REG_MSC_RDTO = to ) +#define __msc_set_cmd(cmd) ( REG_MSC_CMD = cmd ) +#define __msc_set_arg(arg) ( REG_MSC_ARG = arg ) +#define __msc_set_nob(nob) ( REG_MSC_NOB = nob ) +#define __msc_get_nob() ( REG_MSC_NOB ) +#define __msc_set_blklen(len) ( REG_MSC_BLKLEN = len ) +#define __msc_set_cmdat(cmdat) ( REG_MSC_CMDAT = cmdat ) +#define __msc_set_cmdat_ioabort() ( REG_MSC_CMDAT |= MSC_CMDAT_IO_ABORT ) +#define __msc_clear_cmdat_ioabort() ( REG_MSC_CMDAT &= ~MSC_CMDAT_IO_ABORT ) + +#define __msc_set_cmdat_bus_width1() \ +do { \ + REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ + REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_1BIT; \ +} while(0) + +#define __msc_set_cmdat_bus_width4() \ +do { \ + REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ + REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_4BIT; \ +} while(0) + +#define __msc_set_cmdat_dma_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DMA_EN ) +#define __msc_set_cmdat_init() ( REG_MSC_CMDAT |= MSC_CMDAT_INIT ) +#define __msc_set_cmdat_busy() ( REG_MSC_CMDAT |= MSC_CMDAT_BUSY ) +#define __msc_set_cmdat_stream() ( REG_MSC_CMDAT |= MSC_CMDAT_STREAM_BLOCK ) +#define __msc_set_cmdat_block() ( REG_MSC_CMDAT &= ~MSC_CMDAT_STREAM_BLOCK ) +#define __msc_set_cmdat_read() ( REG_MSC_CMDAT &= ~MSC_CMDAT_WRITE_READ ) +#define __msc_set_cmdat_write() ( REG_MSC_CMDAT |= MSC_CMDAT_WRITE_READ ) +#define __msc_set_cmdat_data_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DATA_EN ) + +/* r is MSC_CMDAT_RESPONSE_FORMAT_Rx or MSC_CMDAT_RESPONSE_FORMAT_NONE */ +#define __msc_set_cmdat_res_format(r) \ +do { \ + REG_MSC_CMDAT &= ~MSC_CMDAT_RESPONSE_FORMAT_MASK; \ + REG_MSC_CMDAT |= (r); \ +} while(0) + +#define __msc_clear_cmdat() \ + REG_MSC_CMDAT &= ~( MSC_CMDAT_IO_ABORT | MSC_CMDAT_DMA_EN | MSC_CMDAT_INIT| \ + MSC_CMDAT_BUSY | MSC_CMDAT_STREAM_BLOCK | MSC_CMDAT_WRITE_READ | \ + MSC_CMDAT_DATA_EN | MSC_CMDAT_RESPONSE_FORMAT_MASK ) + +#define __msc_get_imask() ( REG_MSC_IMASK ) +#define __msc_mask_all_intrs() ( REG_MSC_IMASK = 0xff ) +#define __msc_unmask_all_intrs() ( REG_MSC_IMASK = 0x00 ) +#define __msc_mask_rd() ( REG_MSC_IMASK |= MSC_IMASK_RXFIFO_RD_REQ ) +#define __msc_unmask_rd() ( REG_MSC_IMASK &= ~MSC_IMASK_RXFIFO_RD_REQ ) +#define __msc_mask_wr() ( REG_MSC_IMASK |= MSC_IMASK_TXFIFO_WR_REQ ) +#define __msc_unmask_wr() ( REG_MSC_IMASK &= ~MSC_IMASK_TXFIFO_WR_REQ ) +#define __msc_mask_endcmdres() ( REG_MSC_IMASK |= MSC_IMASK_END_CMD_RES ) +#define __msc_unmask_endcmdres() ( REG_MSC_IMASK &= ~MSC_IMASK_END_CMD_RES ) +#define __msc_mask_datatrandone() ( REG_MSC_IMASK |= MSC_IMASK_DATA_TRAN_DONE ) +#define __msc_unmask_datatrandone() ( REG_MSC_IMASK &= ~MSC_IMASK_DATA_TRAN_DONE ) +#define __msc_mask_prgdone() ( REG_MSC_IMASK |= MSC_IMASK_PRG_DONE ) +#define __msc_unmask_prgdone() ( REG_MSC_IMASK &= ~MSC_IMASK_PRG_DONE ) + +/* n=0,1,2,3,4,5,6,7 */ +#define __msc_set_clkrt(n) \ +do { \ + REG_MSC_CLKRT = n; \ +} while(0) + +#define __msc_get_ireg() ( REG_MSC_IREG ) +#define __msc_ireg_rd() ( REG_MSC_IREG & MSC_IREG_RXFIFO_RD_REQ ) +#define __msc_ireg_wr() ( REG_MSC_IREG & MSC_IREG_TXFIFO_WR_REQ ) +#define __msc_ireg_end_cmd_res() ( REG_MSC_IREG & MSC_IREG_END_CMD_RES ) +#define __msc_ireg_data_tran_done() ( REG_MSC_IREG & MSC_IREG_DATA_TRAN_DONE ) +#define __msc_ireg_prg_done() ( REG_MSC_IREG & MSC_IREG_PRG_DONE ) +#define __msc_ireg_clear_end_cmd_res() ( REG_MSC_IREG = MSC_IREG_END_CMD_RES ) +#define __msc_ireg_clear_data_tran_done() ( REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE ) +#define __msc_ireg_clear_prg_done() ( REG_MSC_IREG = MSC_IREG_PRG_DONE ) + +#define __msc_get_stat() ( REG_MSC_STAT ) +#define __msc_stat_not_end_cmd_res() ( (REG_MSC_STAT & MSC_STAT_END_CMD_RES) == 0) +#define __msc_stat_crc_err() \ + ( REG_MSC_STAT & (MSC_STAT_CRC_RES_ERR | MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR_YES) ) +#define __msc_stat_res_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_RES_ERR ) +#define __msc_stat_rd_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_READ_ERROR ) +#define __msc_stat_wr_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_WRITE_ERROR_YES ) +#define __msc_stat_resto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_RES ) +#define __msc_stat_rdto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_READ ) + +#define __msc_rd_resfifo() ( REG_MSC_RES ) +#define __msc_rd_rxfifo() ( REG_MSC_RXFIFO ) +#define __msc_wr_txfifo(v) ( REG_MSC_TXFIFO = v ) + +#define __msc_reset() \ +do { \ + REG_MSC_STRPCL = MSC_STRPCL_RESET; \ + while (REG_MSC_STAT & MSC_STAT_IS_RESETTING); \ +} while (0) + +#define __msc_start_clk() \ +do { \ + REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START; \ +} while (0) + +#define __msc_stop_clk() \ +do { \ + REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP; \ +} while (0) + +#define MMC_CLK 19169200 +#define SD_CLK 24576000 + +/* msc_clk should little than pclk and little than clk retrieve from card */ +#define __msc_calc_clk_divisor(type,dev_clk,msc_clk,lv) \ +do { \ + unsigned int rate, pclk, i; \ + pclk = dev_clk; \ + rate = type?SD_CLK:MMC_CLK; \ + if (msc_clk && msc_clk < pclk) \ + pclk = msc_clk; \ + i = 0; \ + while (pclk < rate) \ + { \ + i ++; \ + rate >>= 1; \ + } \ + lv = i; \ +} while(0) + +/* divide rate to little than or equal to 400kHz */ +#define __msc_calc_slow_clk_divisor(type, lv) \ +do { \ + unsigned int rate, i; \ + rate = (type?SD_CLK:MMC_CLK)/1000/400; \ + i = 0; \ + while (rate > 0) \ + { \ + rate >>= 1; \ + i ++; \ + } \ + lv = i; \ +} while(0) + + +/*************************************************************************** + * SSI + ***************************************************************************/ + +#define __ssi_enable() ( REG_SSI_CR0 |= SSI_CR0_SSIE ) +#define __ssi_disable() ( REG_SSI_CR0 &= ~SSI_CR0_SSIE ) +#define __ssi_select_ce() ( REG_SSI_CR0 &= ~SSI_CR0_FSEL ) + +#define __ssi_normal_mode() ( REG_SSI_ITR &= ~SSI_ITR_IVLTM_MASK ) + +#define __ssi_select_ce2() \ +do { \ + REG_SSI_CR0 |= SSI_CR0_FSEL; \ + REG_SSI_CR1 &= ~SSI_CR1_MULTS; \ +} while (0) + +#define __ssi_select_gpc() \ +do { \ + REG_SSI_CR0 &= ~SSI_CR0_FSEL; \ + REG_SSI_CR1 |= SSI_CR1_MULTS; \ +} while (0) + +#define __ssi_enable_tx_intr() \ + ( REG_SSI_CR0 |= SSI_CR0_TIE | SSI_CR0_TEIE ) + +#define __ssi_disable_tx_intr() \ + ( REG_SSI_CR0 &= ~(SSI_CR0_TIE | SSI_CR0_TEIE) ) + +#define __ssi_enable_rx_intr() \ + ( REG_SSI_CR0 |= SSI_CR0_RIE | SSI_CR0_REIE ) + +#define __ssi_disable_rx_intr() \ + ( REG_SSI_CR0 &= ~(SSI_CR0_RIE | SSI_CR0_REIE) ) + +#define __ssi_enable_loopback() ( REG_SSI_CR0 |= SSI_CR0_LOOP ) +#define __ssi_disable_loopback() ( REG_SSI_CR0 &= ~SSI_CR0_LOOP ) + +#define __ssi_enable_receive() ( REG_SSI_CR0 &= ~SSI_CR0_DISREV ) +#define __ssi_disable_receive() ( REG_SSI_CR0 |= SSI_CR0_DISREV ) + +#define __ssi_finish_receive() \ + ( REG_SSI_CR0 |= (SSI_CR0_RFINE | SSI_CR0_RFINC) ) + +#define __ssi_disable_recvfinish() \ + ( REG_SSI_CR0 &= ~(SSI_CR0_RFINE | SSI_CR0_RFINC) ) + +#define __ssi_flush_txfifo() ( REG_SSI_CR0 |= SSI_CR0_TFLUSH ) +#define __ssi_flush_rxfifo() ( REG_SSI_CR0 |= SSI_CR0_RFLUSH ) + +#define __ssi_flush_fifo() \ + ( REG_SSI_CR0 |= SSI_CR0_TFLUSH | SSI_CR0_RFLUSH ) + +#define __ssi_finish_transmit() ( REG_SSI_CR1 &= ~SSI_CR1_UNFIN ) + +#define __ssi_spi_format() \ +do { \ + REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \ + REG_SSI_CR1 |= SSI_CR1_FMAT_SPI; \ + REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\ + REG_SSI_CR1 |= (SSI_CR1_TFVCK_1 | SSI_CR1_TCKFI_1); \ +} while (0) + +/* TI's SSP format, must clear SSI_CR1.UNFIN */ +#define __ssi_ssp_format() \ +do { \ + REG_SSI_CR1 &= ~(SSI_CR1_FMAT_MASK | SSI_CR1_UNFIN); \ + REG_SSI_CR1 |= SSI_CR1_FMAT_SSP; \ +} while (0) + +/* National's Microwire format, must clear SSI_CR0.RFINE, and set max delay */ +#define __ssi_microwire_format() \ +do { \ + REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \ + REG_SSI_CR1 |= SSI_CR1_FMAT_MW1; \ + REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\ + REG_SSI_CR1 |= (SSI_CR1_TFVCK_3 | SSI_CR1_TCKFI_3); \ + REG_SSI_CR0 &= ~SSI_CR0_RFINE; \ +} while (0) + +/* CE# level (FRMHL), CE# in interval time (ITFRM), + clock phase and polarity (PHA POL), + interval time (SSIITR), interval characters/frame (SSIICR) */ + + /* frmhl,endian,mcom,flen,pha,pol MASK */ +#define SSICR1_MISC_MASK \ + ( SSI_CR1_FRMHL_MASK | SSI_CR1_LFST | SSI_CR1_MCOM_MASK \ + | SSI_CR1_FLEN_MASK | SSI_CR1_PHA | SSI_CR1_POL ) \ + +#define __ssi_spi_set_misc(frmhl,endian,flen,mcom,pha,pol) \ +do { \ + REG_SSI_CR1 &= ~SSICR1_MISC_MASK; \ + REG_SSI_CR1 |= ((frmhl) << 30) | ((endian) << 25) | \ + (((mcom) - 1) << 12) | (((flen) - 2) << 4) | \ + ((pha) << 1) | (pol); \ +} while(0) + +/* Transfer with MSB or LSB first */ +#define __ssi_set_msb() ( REG_SSI_CR1 &= ~SSI_CR1_LFST ) +#define __ssi_set_lsb() ( REG_SSI_CR1 |= SSI_CR1_LFST ) + +#define __ssi_set_frame_length(n) \ + REG_SSI_CR1 = (REG_SSI_CR1 & ~SSI_CR1_FLEN_MASK) | (((n) - 2) << 4) + +/* n = 1 - 16 */ +#define __ssi_set_microwire_command_length(n) \ + ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_MCOM_MASK) | SSI_CR1_MCOM_##n##BIT) ) + +/* Set the clock phase for SPI */ +#define __ssi_set_spi_clock_phase(n) \ + ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_PHA) | (n&0x1)) ) + +/* Set the clock polarity for SPI */ +#define __ssi_set_spi_clock_polarity(n) \ + ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_POL) | (n&0x1)) ) + +/* n = ix8 */ +#define __ssi_set_tx_trigger(n) \ +do { \ + REG_SSI_CR1 &= ~SSI_CR1_TTRG_MASK; \ + REG_SSI_CR1 |= SSI_CR1_TTRG_##n; \ +} while (0) + +/* n = ix8 */ +#define __ssi_set_rx_trigger(n) \ +do { \ + REG_SSI_CR1 &= ~SSI_CR1_RTRG_MASK; \ + REG_SSI_CR1 |= SSI_CR1_RTRG_##n; \ +} while (0) + +#define __ssi_get_txfifo_count() \ + ( (REG_SSI_SR & SSI_SR_TFIFONUM_MASK) >> SSI_SR_TFIFONUM_BIT ) + +#define __ssi_get_rxfifo_count() \ + ( (REG_SSI_SR & SSI_SR_RFIFONUM_MASK) >> SSI_SR_RFIFONUM_BIT ) + +#define __ssi_clear_errors() \ + ( REG_SSI_SR &= ~(SSI_SR_UNDR | SSI_SR_OVER) ) + +#define __ssi_transfer_end() ( REG_SSI_SR & SSI_SR_END ) +#define __ssi_is_busy() ( REG_SSI_SR & SSI_SR_BUSY ) + +#define __ssi_txfifo_full() ( REG_SSI_SR & SSI_SR_TFF ) +#define __ssi_rxfifo_empty() ( REG_SSI_SR & SSI_SR_RFE ) +#define __ssi_rxfifo_noempty() ( REG_SSI_SR & SSI_SR_RFHF ) + +#define __ssi_set_clk(dev_clk, ssi_clk) \ + ( REG_SSI_GR = (dev_clk) / (2*(ssi_clk)) - 1 ) + +#define __ssi_receive_data() REG_SSI_DR +#define __ssi_transmit_data(v) ( REG_SSI_DR = (v) ) + + +/*************************************************************************** + * CIM + ***************************************************************************/ + +#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA ) +#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA ) + +#define __cim_input_data_inverse() ( REG_CIM_CFG |= CIM_CFG_INV_DAT ) +#define __cim_input_data_normal() ( REG_CIM_CFG &= ~CIM_CFG_INV_DAT ) + +#define __cim_vsync_active_low() ( REG_CIM_CFG |= CIM_CFG_VSP ) +#define __cim_vsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_VSP ) + +#define __cim_hsync_active_low() ( REG_CIM_CFG |= CIM_CFG_HSP ) +#define __cim_hsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_HSP ) + +#define __cim_sample_data_at_pclk_falling_edge() \ + ( REG_CIM_CFG |= CIM_CFG_PCP ) +#define __cim_sample_data_at_pclk_rising_edge() \ + ( REG_CIM_CFG &= ~CIM_CFG_PCP ) + +#define __cim_enable_dummy_zero() ( REG_CIM_CFG |= CIM_CFG_DUMMY_ZERO ) +#define __cim_disable_dummy_zero() ( REG_CIM_CFG &= ~CIM_CFG_DUMMY_ZERO ) + +#define __cim_select_external_vsync() ( REG_CIM_CFG |= CIM_CFG_EXT_VSYNC ) +#define __cim_select_internal_vsync() ( REG_CIM_CFG &= ~CIM_CFG_EXT_VSYNC ) + +/* n=0-7 */ +#define __cim_set_data_packing_mode(n) \ +do { \ + REG_CIM_CFG &= ~CIM_CFG_PACK_MASK; \ + REG_CIM_CFG |= (CIM_CFG_PACK_##n); \ +} while (0) + +#define __cim_enable_ccir656_progressive_mode() \ +do { \ + REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ + REG_CIM_CFG |= CIM_CFG_DSM_CPM; \ +} while (0) + +#define __cim_enable_ccir656_interlace_mode() \ +do { \ + REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ + REG_CIM_CFG |= CIM_CFG_DSM_CIM; \ +} while (0) + +#define __cim_enable_gated_clock_mode() \ +do { \ + REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ + REG_CIM_CFG |= CIM_CFG_DSM_GCM; \ +} while (0) + +#define __cim_enable_nongated_clock_mode() \ +do { \ + REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ + REG_CIM_CFG |= CIM_CFG_DSM_NGCM; \ +} while (0) + +/* sclk:system bus clock + * mclk: CIM master clock + */ +#define __cim_set_master_clk(sclk, mclk) \ +do { \ + REG_CIM_CTRL &= ~CIM_CTRL_MCLKDIV_MASK; \ + REG_CIM_CTRL |= (((sclk)/(mclk) - 1) << CIM_CTRL_MCLKDIV_BIT); \ +} while (0) + +#define __cim_enable_sof_intr() \ + ( REG_CIM_CTRL |= CIM_CTRL_DMA_SOFM ) +#define __cim_disable_sof_intr() \ + ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_SOFM ) + +#define __cim_enable_eof_intr() \ + ( REG_CIM_CTRL |= CIM_CTRL_DMA_EOFM ) +#define __cim_disable_eof_intr() \ + ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EOFM ) + +#define __cim_enable_stop_intr() \ + ( REG_CIM_CTRL |= CIM_CTRL_DMA_STOPM ) +#define __cim_disable_stop_intr() \ + ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_STOPM ) + +#define __cim_enable_trig_intr() \ + ( REG_CIM_CTRL |= CIM_CTRL_RXF_TRIGM ) +#define __cim_disable_trig_intr() \ + ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIGM ) + +#define __cim_enable_rxfifo_overflow_intr() \ + ( REG_CIM_CTRL |= CIM_CTRL_RXF_OFM ) +#define __cim_disable_rxfifo_overflow_intr() \ + ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_OFM ) + +/* n=1-16 */ +#define __cim_set_frame_rate(n) \ +do { \ + REG_CIM_CTRL &= ~CIM_CTRL_FRC_MASK; \ + REG_CIM_CTRL |= CIM_CTRL_FRC_##n; \ +} while (0) + +#define __cim_enable_dma() ( REG_CIM_CTRL |= CIM_CTRL_DMA_EN ) +#define __cim_disable_dma() ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EN ) + +#define __cim_reset_rxfifo() ( REG_CIM_CTRL |= CIM_CTRL_RXF_RST ) +#define __cim_unreset_rxfifo() ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_RST ) + +/* n=4,8,12,16,20,24,28,32 */ +#define __cim_set_rxfifo_trigger(n) \ +do { \ + REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIG_MASK; \ + REG_CIM_CTRL |= CIM_CTRL_RXF_TRIG_##n; \ +} while (0) + +#define __cim_clear_state() ( REG_CIM_STATE = 0 ) + +#define __cim_disable_done() ( REG_CIM_STATE & CIM_STATE_VDD ) +#define __cim_rxfifo_empty() ( REG_CIM_STATE & CIM_STATE_RXF_EMPTY ) +#define __cim_rxfifo_reach_trigger() ( REG_CIM_STATE & CIM_STATE_RXF_TRIG ) +#define __cim_rxfifo_overflow() ( REG_CIM_STATE & CIM_STATE_RXF_OF ) +#define __cim_clear_rxfifo_overflow() ( REG_CIM_STATE &= ~CIM_STATE_RXF_OF ) +#define __cim_dma_stop() ( REG_CIM_STATE & CIM_STATE_DMA_STOP ) +#define __cim_dma_eof() ( REG_CIM_STATE & CIM_STATE_DMA_EOF ) +#define __cim_dma_sof() ( REG_CIM_STATE & CIM_STATE_DMA_SOF ) + +#define __cim_get_iid() ( REG_CIM_IID ) +#define __cim_get_image_data() ( REG_CIM_RXFIFO ) +#define __cim_get_dam_cmd() ( REG_CIM_CMD ) + +#define __cim_set_da(a) ( REG_CIM_DA = (a) ) + +/*************************************************************************** + * LCD + ***************************************************************************/ +#define __lcd_as_smart_lcd() ( REG_LCD_CFG |= (1<> LCD_VSYNC_VPS_BIT ) + +#define __lcd_vsync_get_vpe() \ + ( (REG_LCD_VSYNC & LCD_VSYNC_VPE_MASK) >> LCD_VSYNC_VPE_BIT ) +#define __lcd_vsync_set_vpe(n) \ +do { \ + REG_LCD_VSYNC &= ~LCD_VSYNC_VPE_MASK; \ + REG_LCD_VSYNC |= (n) << LCD_VSYNC_VPE_BIT; \ +} while (0) + +#define __lcd_hsync_get_hps() \ + ( (REG_LCD_HSYNC & LCD_HSYNC_HPS_MASK) >> LCD_HSYNC_HPS_BIT ) +#define __lcd_hsync_set_hps(n) \ +do { \ + REG_LCD_HSYNC &= ~LCD_HSYNC_HPS_MASK; \ + REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPS_BIT; \ +} while (0) + +#define __lcd_hsync_get_hpe() \ + ( (REG_LCD_HSYNC & LCD_HSYNC_HPE_MASK) >> LCD_VSYNC_HPE_BIT ) +#define __lcd_hsync_set_hpe(n) \ +do { \ + REG_LCD_HSYNC &= ~LCD_HSYNC_HPE_MASK; \ + REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPE_BIT; \ +} while (0) + +#define __lcd_vat_get_ht() \ + ( (REG_LCD_VAT & LCD_VAT_HT_MASK) >> LCD_VAT_HT_BIT ) +#define __lcd_vat_set_ht(n) \ +do { \ + REG_LCD_VAT &= ~LCD_VAT_HT_MASK; \ + REG_LCD_VAT |= (n) << LCD_VAT_HT_BIT; \ +} while (0) + +#define __lcd_vat_get_vt() \ + ( (REG_LCD_VAT & LCD_VAT_VT_MASK) >> LCD_VAT_VT_BIT ) +#define __lcd_vat_set_vt(n) \ +do { \ + REG_LCD_VAT &= ~LCD_VAT_VT_MASK; \ + REG_LCD_VAT |= (n) << LCD_VAT_VT_BIT; \ +} while (0) + +#define __lcd_dah_get_hds() \ + ( (REG_LCD_DAH & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT ) +#define __lcd_dah_set_hds(n) \ +do { \ + REG_LCD_DAH &= ~LCD_DAH_HDS_MASK; \ + REG_LCD_DAH |= (n) << LCD_DAH_HDS_BIT; \ +} while (0) + +#define __lcd_dah_get_hde() \ + ( (REG_LCD_DAH & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT ) +#define __lcd_dah_set_hde(n) \ +do { \ + REG_LCD_DAH &= ~LCD_DAH_HDE_MASK; \ + REG_LCD_DAH |= (n) << LCD_DAH_HDE_BIT; \ +} while (0) + +#define __lcd_dav_get_vds() \ + ( (REG_LCD_DAV & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT ) +#define __lcd_dav_set_vds(n) \ +do { \ + REG_LCD_DAV &= ~LCD_DAV_VDS_MASK; \ + REG_LCD_DAV |= (n) << LCD_DAV_VDS_BIT; \ +} while (0) + +#define __lcd_dav_get_vde() \ + ( (REG_LCD_DAV & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT ) +#define __lcd_dav_set_vde(n) \ +do { \ + REG_LCD_DAV &= ~LCD_DAV_VDE_MASK; \ + REG_LCD_DAV |= (n) << LCD_DAV_VDE_BIT; \ +} while (0) + +#define __lcd_cmd0_set_sofint() ( REG_LCD_CMD0 |= LCD_CMD_SOFINT ) +#define __lcd_cmd0_clr_sofint() ( REG_LCD_CMD0 &= ~LCD_CMD_SOFINT ) +#define __lcd_cmd1_set_sofint() ( REG_LCD_CMD1 |= LCD_CMD_SOFINT ) +#define __lcd_cmd1_clr_sofint() ( REG_LCD_CMD1 &= ~LCD_CMD_SOFINT ) + +#define __lcd_cmd0_set_eofint() ( REG_LCD_CMD0 |= LCD_CMD_EOFINT ) +#define __lcd_cmd0_clr_eofint() ( REG_LCD_CMD0 &= ~LCD_CMD_EOFINT ) +#define __lcd_cmd1_set_eofint() ( REG_LCD_CMD1 |= LCD_CMD_EOFINT ) +#define __lcd_cmd1_clr_eofint() ( REG_LCD_CMD1 &= ~LCD_CMD_EOFINT ) + +#define __lcd_cmd0_set_pal() ( REG_LCD_CMD0 |= LCD_CMD_PAL ) +#define __lcd_cmd0_clr_pal() ( REG_LCD_CMD0 &= ~LCD_CMD_PAL ) + +#define __lcd_cmd0_get_len() \ + ( (REG_LCD_CMD0 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) +#define __lcd_cmd1_get_len() \ + ( (REG_LCD_CMD1 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) + +/*************************************************************************** + * RTC ops + ***************************************************************************/ + +#define __rtc_write_ready() ( REG_RTC_RCR & RTC_RCR_WRDY ) +#define __rtc_enabled() \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RCR |= RTC_RCR_RTCE ; \ +}while(0) \ + +#define __rtc_disabled() \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RCR &= ~RTC_RCR_RTCE; \ +}while(0) +#define __rtc_enable_alarm() \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RCR |= RTC_RCR_AE; \ +}while(0) + +#define __rtc_disable_alarm() \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RCR &= ~RTC_RCR_AE; \ +}while(0) + +#define __rtc_enable_alarm_irq() \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RCR |= RTC_RCR_AIE; \ +}while(0) + +#define __rtc_disable_alarm_irq() \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RCR &= ~RTC_RCR_AIE; \ +}while(0) +#define __rtc_enable_Hz_irq() \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RCR |= RTC_RCR_HZIE; \ +}while(0) + +#define __rtc_disable_Hz_irq() \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RCR &= ~RTC_RCR_HZIE; \ +}while(0) +#define __rtc_get_1Hz_flag() \ +do{ \ + while(!__rtc_write_ready()); \ + ((REG_RTC_RCR >> RTC_RCR_HZ) & 0x1); \ +}while(0) +#define __rtc_clear_1Hz_flag() \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RCR &= ~RTC_RCR_HZ; \ +}while(0) +#define __rtc_get_alarm_flag() \ +do{ \ + while(!__rtc_write_ready()); \ + ((REG_RTC_RCR >> RTC_RCR_AF) & 0x1); \ +while(0) + +///( (REG_RTC_RCR >> RTC_RCR_AF_BIT) & 0x1 ) + +#define __rtc_clear_alarm_flag() \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RCR &= ~RTC_RCR_AF; \ +}while(0) +//do +#define __rtc_get_second() \ +({ \ + while(!__rtc_write_ready());\ + REG_RTC_RSR; \ +}) +//while(0) + +#define __rtc_set_second(v) \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RSR = v; \ + while(!__rtc_write_ready());\ +}while(0) + +#define __rtc_get_alarm_second() \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RSAR; \ +}while(0) + + +#define __rtc_set_alarm_second(v) \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RSAR = v; \ +}while(0) + +#define __rtc_RGR_is_locked() \ +({ \ + while(!__rtc_write_ready()); \ + REG_RTC_RGR >> RTC_RGR_LOCK; \ +}) +#define __rtc_lock_RGR() \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RGR |= RTC_RGR_LOCK; \ +}while(0) + +#define __rtc_unlock_RGR() \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RGR &= ~RTC_RGR_LOCK; \ +}while(0) + +#define __rtc_get_adjc_val() \ +do{ \ + while(!__rtc_write_ready()); \ + ( (REG_RTC_RGR & RTC_RGR_ADJC_MASK) >> RTC_RGR_ADJC_BIT ); \ +}while(0) +#define __rtc_set_adjc_val(v) \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RGR = (REG_RTC_RGR & (~RTC_RGR_ADJC_MASK)) |(v << RTC_RGR_ADJC_BIT); \ +}while(0) + +#define __rtc_get_nc1Hz_val() \ + ( (REG_RTC_RGR & RTC_RGR_NC1HZ_MASK) >> RTC_RGR_NC1HZ_BIT ) + +#define __rtc_set_nc1Hz_val(v) \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_RGR = (REG_RTC_RGR & (~RTC_RGR_NC1HZ_MASK)) | (v << RTC_RGR_NC1HZ_BIT);\ +}while(0) +#define __rtc_power_down() \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_HCR |= RTC_HCR_PD; \ +}while(0) + +#define __rtc_get_hwfcr_val() \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_HWFCR & RTC_HWFCR_MASK; \ +}while(0) +#define __rtc_set_hwfcr_val(v) \ +do{ \ + while(!__rtc_write_ready()); \ + REG_RTC_HWFCR = (v) & RTC_HWFCR_MASK; \ +}while(0) + +#define __rtc_get_hrcr_val() \ +do{ \ + while(!__rtc_write_ready()); \ + ( REG_RTC_HRCR & RTC_HRCR_MASK ); \ +}while(0) +#define __rtc_set_hrcr_val(v) \ +do{ \ + while(!__rtc_write_ready()); \ + ( REG_RTC_HRCR = (v) & RTC_HRCR_MASK ); \ +}while(0) + +#define __rtc_enable_alarm_wakeup() \ +do{ \ + while(!__rtc_write_ready()); \ + ( REG_RTC_HWCR |= RTC_HWCR_EALM ); \ +}while(0) + +#define __rtc_disable_alarm_wakeup() \ +do{ \ + while(!__rtc_write_ready()); \ + ( REG_RTC_HWCR &= ~RTC_HWCR_EALM ); \ +}while(0) + +#define __rtc_status_hib_reset_occur() \ +({ \ + (REG_RTC_HWRSR & RTC_HWRSR_HR); \ +}) +#define __rtc_status_ppr_reset_occur() \ +do{ \ + while(!__rtc_write_ready()); \ + ( (REG_RTC_HWRSR & RTC_HWRSR_PPR) & 0x1 ); \ +}while(0) +#define __rtc_status_wakeup_pin_waken_up() \ +do{ \ + while(!__rtc_write_ready()); \ + ( (REG_RTC_HWRSR >> RTC_HWRSR_PIN) & 0x1 ); \ +}while(0) +#define __rtc_status_alarm_waken_up() \ +do{ \ + while(!__rtc_write_ready()); \ + ( (REG_RTC_HWRSR >> RTC_HWRSR_ALM) & 0x1 ); \ +}while(0) +#define __rtc_clear_hib_stat_all() \ +do{ \ + while(!__rtc_write_ready()); \ + ( REG_RTC_HWRSR = 0 ); \ +}while(0) + +#define __rtc_get_scratch_pattern() \ +({ while(!__rtc_write_ready()); \ + (REG_RTC_HSPR);}) +#define __rtc_set_scratch_pattern(n) \ +do{ \ + while(!__rtc_write_ready()); \ + (REG_RTC_HSPR = n ); \ +}while(0) + + +#endif /* !__ASSEMBLY__ */ + + +#ifndef _IPU_H_ +#define _IPU_H_ + +// IPU_REG_BASE +#define IPU_P_BASE 0x13080000 +#define IPU_V_BASE 0xB3080000 +#define IPU__SIZE 0x00001000 + +struct ipu_module +{ + unsigned int reg_ctrl; // 0x0 + unsigned int reg_status; // 0x4 + unsigned int reg_d_fmt; // 0x8 + unsigned int reg_y_addr; // 0xc + unsigned int reg_u_addr; // 0x10 + unsigned int reg_v_addr; // 0x14 + unsigned int reg_in_fm_gs; // 0x18 + unsigned int reg_y_stride; // 0x1c + unsigned int reg_uv_stride; // 0x20 + unsigned int reg_out_addr; // 0x24 + unsigned int reg_out_gs; // 0x28 + unsigned int reg_out_stride; // 0x2c + unsigned int rsz_coef_index; // 0x30 + unsigned int reg_csc_c0_coef; // 0x34 + unsigned int reg_csc_c1_coef; // 0x38 + unsigned int reg_csc_c2_coef; // 0x3c + unsigned int reg_csc_c3_coef; // 0x40 + unsigned int reg_csc_c4_coef; // 0x44 + unsigned int hrsz_coef_lut[20]; // 0x48 + unsigned int vrsz_coef_lut[20]; // 0x98 +}; + +typedef struct +{ + unsigned int coef; + unsigned short int in_n; + unsigned short int out_n; +} rsz_lut; + +struct Ration2m +{ + float ratio; + int n, m; +}; + + +// Register offset +#define REG_CTRL 0x0 +#define REG_STATUS 0x4 +#define REG_D_FMT 0x8 +#define REG_Y_ADDR 0xc +#define REG_U_ADDR 0x10 +#define REG_V_ADDR 0x14 +#define REG_IN_FM_GS 0x18 +#define REG_Y_STRIDE 0x1c +#define REG_UV_STRIDE 0x20 +#define REG_OUT_ADDR 0x24 +#define REG_OUT_GS 0x28 +#define REG_OUT_STRIDE 0x2c +#define REG_RSZ_COEF_INDEX 0x30 +#define REG_CSC_C0_COEF 0x34 +#define REG_CSC_C1_COEF 0x38 +#define REG_CSC_C2_COEF 0x3c +#define REG_CSC_C3_COEF 0x40 +#define REG_CSC_C4_COEF 0x44 +#define HRSZ_LUT_BASE 0x48 +#define VRSZ_LUT_BASE 0x98 + +// REG_CTRL field define +#define IPU_EN (1 << 0) +#define RSZ_EN (1 << 1) +#define FM_IRQ_EN (1 << 2) +#define IPU_RESET (1 << 3) +#define H_UP_SCALE (1 << 8) +#define V_UP_SCALE (1 << 9) +#define H_SCALE_SHIFT (8) +#define V_SCALE_SHIFT (9) + +// REG_STATUS field define +#define OUT_END (1 << 0) + +// REG_D_FMT field define +#define INFMT_YUV420 (0 << 0) +#define INFMT_YUV422 (1 << 0) +#define INFMT_YUV444 (2 << 0) +#define INFMT_YUV411 (3 << 0) +#define INFMT_YCbCr420 (4 << 0) +#define INFMT_YCbCr422 (5 << 0) +#define INFMT_YCbCr444 (6 << 0) +#define INFMT_YCbCr411 (7 << 0) +#define INFMT_MASK (7) + +#define OUTFMT_RGB555 (0 << 16) +#define OUTFMT_RGB565 (1 << 16) +#define OUTFMT_RGB888 (2 << 16) +#define OUTFMT_MASK (3 << 16) + +// REG_IN_FM_GS field define +#define IN_FM_W(val) ((val) << 16) +#define IN_FM_H(val) ((val) << 0) + +// REG_IN_FM_GS field define +#define OUT_FM_W(val) ((val) << 16) +#define OUT_FM_H(val) ((val) << 0) + +// REG_UV_STRIDE field define +#define U_STRIDE(val) ((val) << 16) +#define V_STRIDE(val) ((val) << 0) + +#define VE_IDX_SFT 0 +#define HE_IDX_SFT 16 + +// RSZ_LUT_FIELD +#define OUT_N_SFT 0 +#define OUT_N_MSK 0x1 +#define IN_N_SFT 1 +#define IN_N_MSK 0x1 +#define W_COEF_SFT 2 +#define W_COEF_MSK 0xFF + +// function about REG_CTRL +#define IPU_STOP_IPU() \ + REG32(IPU_V_BASE + REG_CTRL) &= ~IPU_EN; + +#define IPU_RUN_IPU() \ + REG32(IPU_V_BASE + REG_CTRL) |= IPU_EN; + +#define IPU_RESET_IPU() \ + REG32(IPU_V_BASE + REG_CTRL) |= IPU_RESET; + +#define IPU_DISABLE_IRQ() \ + REG32(IPU_V_BASE + REG_CTRL) &= ~FM_IRQ_EN; + +#define IPU_ENABLE_IRQ() \ + REG32(IPU_V_BASE + REG_CTRL) |= FM_IRQ_EN; + +#define IPU_DISABLE_RSIZE() \ + REG32(IPU_V_BASE + REG_CTRL) &= ~RSZ_EN; + +#define IPU_ENABLE_RSIZE() \ + REG32(IPU_V_BASE + REG_CTRL) |= RSZ_EN; + +#define IPU_IS_ENABLED() \ + (REG32(IPU_V_BASE + REG_CTRL) & IPU_EN) + +// function about REG_STATUS +#define IPU_CLEAR_END_FLAG() \ + REG32(IPU_V_BASE + REG_STATUS) &= ~OUT_END; + +#define IPU_POLLING_END_FLAG() \ + (REG32(IPU_V_BASE + REG_STATUS) & OUT_END) + +#define IPU_SET_INFMT(fmt) \ + REG32(IPU_V_BASE + REG_D_FMT) = (REG32(IPU_V_BASE + REG_D_FMT) & ~INFMT_MASK) | (fmt); + +#define IPU_SET_OUTFMT(fmt) \ + REG32(IPU_V_BASE + REG_D_FMT) = (REG32(IPU_V_BASE + REG_D_FMT) & ~OUTFMT_MASK) | (fmt); + +#define IPU_SET_IN_FM(w, h) \ + REG32(IPU_V_BASE + REG_IN_FM_GS) = IN_FM_W(w) | IN_FM_H(h); + +#define IPU_SET_Y_STRIDE(stride) \ + REG32(IPU_V_BASE + REG_Y_STRIDE) = (stride); + +#define IPU_SET_UV_STRIDE(u, v) \ + REG32(IPU_V_BASE + REG_UV_STRIDE) = U_STRIDE(u) | V_STRIDE(v); + +#define IPU_SET_Y_ADDR(addr) \ + REG32(IPU_V_BASE + REG_Y_ADDR) = (addr); + +#define IPU_SET_U_ADDR(addr) \ + REG32(IPU_V_BASE + REG_U_ADDR) = (addr); + +#define IPU_SET_V_ADDR(addr) \ + REG32(IPU_V_BASE + REG_V_ADDR) = (addr); + +#define IPU_SET_OUT_ADDR(addr) \ + REG32(IPU_V_BASE + REG_OUT_ADDR) = (addr); + +#define IPU_SET_OUT_FM(w, h) \ + REG32(IPU_V_BASE + REG_OUT_GS) = OUT_FM_W(w) | OUT_FM_H(h); + +#define IPU_SET_OUT_STRIDE(stride) \ + REG32(IPU_V_BASE + REG_OUT_STRIDE) = (stride); + +#define IPU_SET_CSC_C0_COEF(coef) \ + REG32(IPU_V_BASE + REG_CSC_C0_COEF) = (coef); + +#define IPU_SET_CSC_C1_COEF(coef) \ + REG32(IPU_V_BASE + REG_CSC_C1_COEF) = (coef); + +#define IPU_SET_CSC_C2_COEF(coef) \ + REG32(IPU_V_BASE + REG_CSC_C2_COEF) = (coef); + +#define IPU_SET_CSC_C3_COEF(coef) \ + REG32(IPU_V_BASE + REG_CSC_C3_COEF) = (coef); + +#define IPU_SET_CSC_C4_COEF(coef) \ + REG32(IPU_V_BASE + REG_CSC_C4_COEF) = (coef); + +/* YCbCr */ +/* parameter + R = 1.164 * (Y - 16) + 1.596 * (cr - 128) {C0, C1} + G = 1.164 * (Y - 16) - 0.392 * (cb -128) - 0.813 * (cr - 128) {C0, C2, C3} + B = 1.164 * (Y - 16) + 2.017 * (cb - 128) {C0, C4} +*/ +#define YCBCR_CSC_C0 0x4A8 /* 1.164 * 1024 */ +#define YCBCR_CSC_C1 0x662 /* 1.596 * 1024 */ +#define YCBCR_CSC_C2 0x191 /* 0.392 * 1024 */ +#define YCBCR_CSC_C3 0x341 /* 0.813 * 1024 */ +#define YCBCR_CSC_C4 0x811 /* 2.017 * 1024 */ + + +/* YUV */ +/* parameter + R = 1 * (Y – 0) + 1.4026 * (V - 128) {C0, C1} + G = 1 * (Y – 0) – 0.3444 * (U - 128) – 0.7144 * (V - 128) {C0, C2, C3} + B = 1 * (Y – 0) + 1.7730 * (U - 128) {C0, C4} +*/ +#define YUV_CSC_C0 0x400 +#define YUV_CSC_C1 0x59C +#define YUV_CSC_C2 0x161 +#define YUV_CSC_C3 0x2DC +#define YUV_CSC_C4 0x718 + +#endif /* _IPU_H_ */ + +/* Rockbox USB defines */ +#define USB_NUM_ENDPOINTS 3 +#define USB_DEVBSS_ATTR IBSS_ATTR + +#endif /* __JZ4740_H__ */ diff --git a/project/jni/application/quake/source/keys.c b/project/jni/application/quake/source/keys.c new file mode 100644 index 000000000..82dd61dba --- /dev/null +++ b/project/jni/application/quake/source/keys.c @@ -0,0 +1,798 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "quakedef.h" + +/* + +key up events are sent even if in console mode + +*/ + + +#define MAXCMDLINE 256 +char key_lines[32][MAXCMDLINE]; +int key_linepos; +int shift_down=false; +int key_lastpress; + +int edit_line=0; +int history_line=0; + +keydest_t key_dest; + +int key_count; // incremented every key event + +char *keybindings[256]; +qboolean consolekeys[256]; // if true, can't be rebound while in console +qboolean menubound[256]; // if true, can't be rebound while in menu +int keyshift[256]; // key to map to if shift held down in console +int key_repeats[256]; // if > 1, it is autorepeating +qboolean keydown[256]; + +typedef struct +{ + char *name; + int keynum; +} keyname_t; + +keyname_t keynames[] = +{ + {"TAB", K_TAB}, + {"ENTER", K_ENTER}, + {"ESCAPE", K_ESCAPE}, + {"SPACE", K_SPACE}, + {"BACKSPACE", K_BACKSPACE}, + {"UPARROW", K_UPARROW}, + {"DOWNARROW", K_DOWNARROW}, + {"LEFTARROW", K_LEFTARROW}, + {"RIGHTARROW", K_RIGHTARROW}, + + {"ALT", K_ALT}, + {"CTRL", K_CTRL}, + {"SHIFT", K_SHIFT}, + + {"F1", K_F1}, + {"F2", K_F2}, + {"F3", K_F3}, + {"F4", K_F4}, + {"F5", K_F5}, + {"F6", K_F6}, + {"F7", K_F7}, + {"F8", K_F8}, + {"F9", K_F9}, + {"F10", K_F10}, + {"F11", K_F11}, + {"F12", K_F12}, + + {"INS", K_INS}, + {"DEL", K_DEL}, + {"PGDN", K_PGDN}, + {"PGUP", K_PGUP}, + {"HOME", K_HOME}, + {"END", K_END}, + + {"MOUSE1", K_MOUSE1}, + {"MOUSE2", K_MOUSE2}, + {"MOUSE3", K_MOUSE3}, + + {"JOY1", K_JOY1}, + {"JOY2", K_JOY2}, + {"JOY3", K_JOY3}, + {"JOY4", K_JOY4}, + + {"AUX1", K_AUX1}, + {"AUX2", K_AUX2}, + {"AUX3", K_AUX3}, + {"AUX4", K_AUX4}, + {"AUX5", K_AUX5}, + {"AUX6", K_AUX6}, + {"AUX7", K_AUX7}, + {"AUX8", K_AUX8}, + {"AUX9", K_AUX9}, + {"AUX10", K_AUX10}, + {"AUX11", K_AUX11}, + {"AUX12", K_AUX12}, + {"AUX13", K_AUX13}, + {"AUX14", K_AUX14}, + {"AUX15", K_AUX15}, + {"AUX16", K_AUX16}, + {"AUX17", K_AUX17}, + {"AUX18", K_AUX18}, + {"AUX19", K_AUX19}, + {"AUX20", K_AUX20}, + {"AUX21", K_AUX21}, + {"AUX22", K_AUX22}, + {"AUX23", K_AUX23}, + {"AUX24", K_AUX24}, + {"AUX25", K_AUX25}, + {"AUX26", K_AUX26}, + {"AUX27", K_AUX27}, + {"AUX28", K_AUX28}, + {"AUX29", K_AUX29}, + {"AUX30", K_AUX30}, + {"AUX31", K_AUX31}, + {"AUX32", K_AUX32}, + + {"PAUSE", K_PAUSE}, + + {"MWHEELUP", K_MWHEELUP}, + {"MWHEELDOWN", K_MWHEELDOWN}, + + {"SEMICOLON", ';'}, // because a raw semicolon seperates commands + + {NULL,0} +}; + +/* +============================================================================== + + LINE TYPING INTO THE CONSOLE + +============================================================================== +*/ + + +/* +==================== +Key_Console + +Interactive line editing and console scrollback +==================== +*/ +void Key_Console (int key) +{ + char *cmd; + + if (key == K_ENTER|| key==K_JOY1 ) + { + Cbuf_AddText (key_lines[edit_line]+1); // skip the > + Cbuf_AddText ("\n"); + Con_Printf ("%s\n",key_lines[edit_line]); + edit_line = (edit_line + 1) & 31; + history_line = edit_line; + key_lines[edit_line][0] = ']'; + key_linepos = 1; + if (cls.state == ca_disconnected) + SCR_UpdateScreen (); // force an update, because the command + // may take some time + return; + } + + if (key == K_TAB) + { // command completion + cmd = Cmd_CompleteCommand (key_lines[edit_line]+1); + if (!cmd) + cmd = Cvar_CompleteVariable (key_lines[edit_line]+1); + if (cmd) + { + Q_strcpy (key_lines[edit_line]+1, cmd); + key_linepos = Q_strlen(cmd)+1; + key_lines[edit_line][key_linepos] = ' '; + key_linepos++; + key_lines[edit_line][key_linepos] = 0; + return; + } + } + + if (key == K_BACKSPACE || key == K_LEFTARROW) + { + if (key_linepos > 1) + key_linepos--; + return; + } + + if (key == K_UPARROW) + { + do + { + history_line = (history_line - 1) & 31; + } while (history_line != edit_line + && !key_lines[history_line][1]); + if (history_line == edit_line) + history_line = (edit_line+1)&31; + Q_strcpy(key_lines[edit_line], key_lines[history_line]); + key_linepos = Q_strlen(key_lines[edit_line]); + return; + } + + if (key == K_DOWNARROW) + { + if (history_line == edit_line) return; + do + { + history_line = (history_line + 1) & 31; + } + while (history_line != edit_line + && !key_lines[history_line][1]); + if (history_line == edit_line) + { + key_lines[edit_line][0] = ']'; + key_linepos = 1; + } + else + { + Q_strcpy(key_lines[edit_line], key_lines[history_line]); + key_linepos = Q_strlen(key_lines[edit_line]); + } + return; + } + + if (key == K_PGUP || key==K_MWHEELUP) + { + con_backscroll += 2; + if ((unsigned int)con_backscroll > con_totallines - (vid.height>>3) - 1) + con_backscroll = con_totallines - (vid.height>>3) - 1; + return; + } + + if (key == K_PGDN || key==K_MWHEELDOWN) + { + con_backscroll -= 2; + if (con_backscroll < 0) + con_backscroll = 0; + return; + } + + if (key == K_HOME) + { + con_backscroll = con_totallines - (vid.height>>3) - 1; + return; + } + + if (key == K_END) + { + con_backscroll = 0; + return; + } + + if (key < 32 || key > 127) + return; // non printable + + if (key_linepos < MAXCMDLINE-1) + { + key_lines[edit_line][key_linepos] = key; + key_linepos++; + key_lines[edit_line][key_linepos] = 0; + } + +} + +//============================================================================ + +char chat_buffer[32]; +qboolean team_message = false; + +void Key_Message (int key) +{ + static int chat_bufferlen = 0; + + if (key == K_ENTER) + { + if (team_message) + Cbuf_AddText ("say_team \""); + else + Cbuf_AddText ("say \""); + Cbuf_AddText(chat_buffer); + Cbuf_AddText("\"\n"); + + key_dest = key_game; + chat_bufferlen = 0; + chat_buffer[0] = 0; + return; + } + + if (key == K_ESCAPE) + { + key_dest = key_game; + chat_bufferlen = 0; + chat_buffer[0] = 0; + return; + } + + if (key < 32 || key > 127) + return; // non printable + + if (key == K_BACKSPACE) + { + if (chat_bufferlen) + { + chat_bufferlen--; + chat_buffer[chat_bufferlen] = 0; + } + return; + } + + if (chat_bufferlen == 31) + return; // all full + + chat_buffer[chat_bufferlen++] = key; + chat_buffer[chat_bufferlen] = 0; +} + +//============================================================================ + + +/* +=================== +Key_StringToKeynum + +Returns a key number to be used to index keybindings[] by looking at +the given string. Single ascii characters return themselves, while +the K_* names are matched up. +=================== +*/ +int Key_StringToKeynum (char *str) +{ + keyname_t *kn; + + if (!str || !str[0]) + return -1; + if (!str[1]) + return str[0]; + + for (kn=keynames ; kn->name ; kn++) + { + if (!Q_strcasecmp(str,kn->name)) + return kn->keynum; + } + return -1; +} + +/* +=================== +Key_KeynumToString + +Returns a string (either a single ascii char, or a K_* name) for the +given keynum. +FIXME: handle quote special (general escape sequence?) +=================== +*/ +char *Key_KeynumToString (int keynum) +{ + keyname_t *kn; + static char tinystr[2]; + + if (keynum == -1) + return ""; + if (keynum > 32 && keynum < 127) + { // printable ascii + tinystr[0] = keynum; + tinystr[1] = 0; + return tinystr; + } + + for (kn=keynames ; kn->name ; kn++) + if (keynum == kn->keynum) + return kn->name; + + return ""; +} + + +/* +=================== +Key_SetBinding +=================== +*/ +void Key_SetBinding (int keynum, char *binding) +{ + char *new; + int l; + + if (keynum == -1) + return; + +// free old bindings + if (keybindings[keynum]) + { + Z_Free (keybindings[keynum]); + keybindings[keynum] = NULL; + } + +// allocate memory for new binding + l = Q_strlen (binding); + new = Z_Malloc (l+1); + Q_strcpy (new, binding); + new[l] = 0; + keybindings[keynum] = new; +} + +/* +=================== +Key_Unbind_f +=================== +*/ +void Key_Unbind_f (void) +{ + int b; + + if (Cmd_Argc() != 2) + { + Con_Printf ("unbind : remove commands from a key\n"); + return; + } + + b = Key_StringToKeynum (Cmd_Argv(1)); + if (b==-1) + { + Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1)); + return; + } + + Key_SetBinding (b, ""); +} + +void Key_Unbindall_f (void) +{ + int i; + + for (i=0 ; i<256 ; i++) + if (keybindings[i]) + Key_SetBinding (i, ""); +} + + +/* +=================== +Key_Bind_f +=================== +*/ +void Key_Bind_f (void) +{ + int i, c, b; + char cmd[1024]; + + c = Cmd_Argc(); + + if (c != 2 && c != 3) + { + Con_Printf ("bind [command] : attach a command to a key\n"); + return; + } + b = Key_StringToKeynum (Cmd_Argv(1)); + if (b==-1) + { + Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1)); + return; + } + + if (c == 2) + { + if (keybindings[b]) + Con_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] ); + else + Con_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) ); + return; + } + +// copy the rest of the command line + cmd[0] = 0; // start out with a null string + for (i=2 ; i< c ; i++) + { + if (i > 2) + strcat (cmd, " "); + strcat (cmd, Cmd_Argv(i)); + } + + Key_SetBinding (b, cmd); +} + +/* +============ +Key_WriteBindings + +Writes lines containing "bind key value" +============ +*/ +void Key_WriteBindings (FILE *f) +{ + int i; + + for (i=0 ; i<256 ; i++) + if (keybindings[i]) + if (*keybindings[i]) + fprintf (f, "bind \"%s\" \"%s\"\n", Key_KeynumToString(i), keybindings[i]); +} + + +/* +=================== +Key_Init +=================== +*/ +void Key_Init (void) +{ + int i; + + for (i=0 ; i<32 ; i++) + { + key_lines[i][0] = ']'; + key_lines[i][1] = 0; + } + key_linepos = 1; + +// +// init ascii characters in console mode +// + for (i=32 ; i<128 ; i++) + consolekeys[i] = true; + consolekeys[K_ENTER] = true; + consolekeys[K_TAB] = true; + consolekeys[K_LEFTARROW] = true; + consolekeys[K_RIGHTARROW] = true; + consolekeys[K_UPARROW] = true; + consolekeys[K_DOWNARROW] = true; + consolekeys[K_BACKSPACE] = true; + consolekeys[K_PGUP] = true; + consolekeys[K_PGDN] = true; + consolekeys[K_SHIFT] = true; + consolekeys[K_MWHEELUP] = true; + consolekeys[K_MWHEELDOWN] = true; + consolekeys[K_JOY1] = true; + consolekeys['`'] = false; + consolekeys['~'] = false; + + for (i=0 ; i<256 ; i++) + keyshift[i] = i; + for (i='a' ; i<='z' ; i++) + keyshift[i] = i - 'a' + 'A'; + keyshift['1'] = '!'; + keyshift['2'] = '@'; + keyshift['3'] = '#'; + keyshift['4'] = '$'; + keyshift['5'] = '%'; + keyshift['6'] = '^'; + keyshift['7'] = '&'; + keyshift['8'] = '*'; + keyshift['9'] = '('; + keyshift['0'] = ')'; + keyshift['-'] = '_'; + keyshift['='] = '+'; + keyshift[','] = '<'; + keyshift['.'] = '>'; + keyshift['/'] = '?'; + keyshift[';'] = ':'; + keyshift['\''] = '"'; + keyshift['['] = '{'; + keyshift[']'] = '}'; + keyshift['`'] = '~'; + keyshift['\\'] = '|'; + + menubound[K_ESCAPE] = true; + for (i=0 ; i<12 ; i++) + menubound[K_F1+i] = true; + +// +// register our functions +// + Cmd_AddCommand ("bind",Key_Bind_f); + Cmd_AddCommand ("unbind",Key_Unbind_f); + Cmd_AddCommand ("unbindall",Key_Unbindall_f); + + //Dan East: Allow our skin keys to register when menu is up +#ifdef _ARM_ + menubound[K_AUX5]=true; +#elif defined(_MIPS_) + menubound[K_AUX2]=true; +#else + //Don't know what this should be for HP, etc. + menubound[K_AUX5]=true; +#endif +} + +/* +=================== +Key_Event + +Called by the system between frames for both key up and key down events +Should NOT be called during an interrupt! +=================== +*/ +void Key_Event (int key, qboolean down) +{ + char *kb; + char cmd[1024]; + + keydown[key] = down; + + if (!down) + key_repeats[key] = 0; + + key_lastpress = key; + key_count++; + if (key_count <= 0) + { + return; // just catching keys for Con_NotifyBox + } + +// update auto-repeat status + if (down) + { + key_repeats[key]++; + if (key != K_BACKSPACE && key != K_PAUSE && key_repeats[key] > 1) + { + return; // ignore most autorepeats + } + + if (key >= 200 && !keybindings[key]) + Con_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) ); + } + + if (key == K_SHIFT) + shift_down = down; + +// +// handle escape specialy, so the user can never unbind it +// + if (key == K_ESCAPE) + { + if (!down) + return; + switch (key_dest) + { + case key_message: + Key_Message (key); + break; + case key_menu: + M_Keydown (key); + break; + case key_game: + case key_console: + M_ToggleMenu_f (); + break; + default: + Sys_Error ("Bad key_dest"); + } + return; + } + +// +// key up events only generate commands if the game key binding is +// a button command (leading + sign). These will occur even in console mode, +// to keep the character from continuing an action started before a console +// switch. Button commands include the kenum as a parameter, so multiple +// downs can be matched with ups +// + if (!down) + { + kb = keybindings[key]; + if (kb && kb[0] == '+') + { + sprintf (cmd, "-%s %i\n", kb+1, key); + Cbuf_AddText (cmd); + } + if (keyshift[key] != key) + { + kb = keybindings[keyshift[key]]; + if (kb && kb[0] == '+') + { + sprintf (cmd, "-%s %i\n", kb+1, key); + Cbuf_AddText (cmd); + } + } + return; + } + +// +// during demo playback, most keys bring up the main menu +// + if (cls.demoplayback && down && consolekeys[key] && key_dest == key_game) + { + M_ToggleMenu_f (); + return; + } + +// +// if not a consolekey, send to the interpreter no matter what mode is +// + if ( (key_dest == key_menu && menubound[key]) + || (key_dest == key_console && !consolekeys[key]) + || (key_dest == key_game && ( !con_forcedup || !consolekeys[key] ) ) ) + { + kb = keybindings[key]; + if (kb) + { + if (kb[0] == '+') + { // button commands add keynum as a parm + sprintf (cmd, "%s %i\n", kb, key); + Cbuf_AddText (cmd); + } + else + { + Cbuf_AddText (kb); + Cbuf_AddText ("\n"); + } + } + return; + } + + if (!down) + return; // other systems only care about key down events + + if (shift_down) + { + key = keyshift[key]; + } + + switch (key_dest) + { + case key_message: + Key_Message (key); + break; + case key_menu: + M_Keydown (key); + break; + + case key_game: + case key_console: + Key_Console (key); + break; + default: + Sys_Error ("Bad key_dest"); + } +} + +void Key_Extra (int *key) { + if (keydown[K_CTRL]) { + if (*key >= '0' && *key <= '9') { + *key = *key - '0' + 0x12; + } else { + switch (*key) { + case '[': *key = 0x10; break; + case ']': *key = 0x11; break; + case 'g': *key = 0x86; break; + case 'r': *key = 0x87; break; + case 'y': *key = 0x88; break; + case 'b': *key = 0x89; break; + case '(': *key = 0x80; break; + case '=': *key = 0x81; break; + case ')': *key = 0x82; break; + case 'a': *key = 0x83; break; + case '<': *key = 0x1d; break; + case '-': *key = 0x1e; break; + case '>': *key = 0x1f; break; + case ',': *key = 0x1c; break; + case '.': *key = 0x9c; break; + case 'B': *key = 0x8b; break; + case 'C': *key = 0x8d; break; + } + } + } + + if (keydown[K_ALT]) + *key |= 0x80; +} + +/* +=================== +Key_ClearStates +=================== +*/ +void Key_ClearStates (void) +{ + int i; + + for (i=0 ; i<256 ; i++) + { + keydown[i] = false; + key_repeats[i] = 0; + } +} + diff --git a/project/jni/application/quake/source/keys.h b/project/jni/application/quake/source/keys.h new file mode 100644 index 000000000..4b575f2b5 --- /dev/null +++ b/project/jni/application/quake/source/keys.h @@ -0,0 +1,134 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// +// these are the key numbers that should be passed to Key_Event +// +#define K_TAB 9 +#define K_ENTER 13 +#define K_ESCAPE 27 +#define K_SPACE 32 + +// normal keys should be passed as lowercased ascii + +#define K_BACKSPACE 127 +#define K_UPARROW 128 +#define K_DOWNARROW 129 +#define K_LEFTARROW 130 +#define K_RIGHTARROW 131 + +#define K_ALT 132 +#define K_CTRL 133 +#define K_SHIFT 134 +#define K_F1 135 +#define K_F2 136 +#define K_F3 137 +#define K_F4 138 +#define K_F5 139 +#define K_F6 140 +#define K_F7 141 +#define K_F8 142 +#define K_F9 143 +#define K_F10 144 +#define K_F11 145 +#define K_F12 146 +#define K_INS 147 +#define K_DEL 148 +#define K_PGDN 149 +#define K_PGUP 150 +#define K_HOME 151 +#define K_END 152 + +#define K_PAUSE 255 + +// +// mouse buttons generate virtual keys +// +#define K_MOUSE1 200 +#define K_MOUSE2 201 +#define K_MOUSE3 202 + +// +// joystick buttons +// +#define K_JOY1 203 +#define K_JOY2 204 +#define K_JOY3 205 +#define K_JOY4 206 + +// +// aux keys are for multi-buttoned joysticks to generate so they can use +// the normal binding process +// +#define K_AUX1 207 +#define K_AUX2 208 +#define K_AUX3 209 +#define K_AUX4 210 +#define K_AUX5 211 +#define K_AUX6 212 +#define K_AUX7 213 +#define K_AUX8 214 +#define K_AUX9 215 +#define K_AUX10 216 +#define K_AUX11 217 +#define K_AUX12 218 +#define K_AUX13 219 +#define K_AUX14 220 +#define K_AUX15 221 +#define K_AUX16 222 +#define K_AUX17 223 +#define K_AUX18 224 +#define K_AUX19 225 +#define K_AUX20 226 +#define K_AUX21 227 +#define K_AUX22 228 +#define K_AUX23 229 +#define K_AUX24 230 +#define K_AUX25 231 +#define K_AUX26 232 +#define K_AUX27 233 +#define K_AUX28 234 +#define K_AUX29 235 +#define K_AUX30 236 +#define K_AUX31 237 +#define K_AUX32 238 + +// JACK: Intellimouse(c) Mouse Wheel Support + +#define K_MWHEELUP 239 +#define K_MWHEELDOWN 240 + + + +typedef enum {key_game, key_console, key_message, key_menu} keydest_t; + +extern keydest_t key_dest; +extern char *keybindings[256]; +extern int key_repeats[256]; +extern int key_count; // incremented every key event +extern int key_lastpress; + +void Key_Event (int key, qboolean down); +void Key_Init (void); +void Key_WriteBindings (FILE *f); +void Key_SetBinding (int keynum, char *binding); +void Key_Extra (int *key); +void Key_ClearStates (void); + diff --git a/project/jni/application/quake/source/mathlib.c b/project/jni/application/quake/source/mathlib.c new file mode 100644 index 000000000..7ad7b152a --- /dev/null +++ b/project/jni/application/quake/source/mathlib.c @@ -0,0 +1,1224 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// mathlib.c -- math primitives + +//Dan East: +//I've made many additions to this file, recreating various original functions to use +//my Fixed Point Math routines. My additions all contain the acronym FPM + +#include +#include "quakedef.h" + +void Sys_Error (char *error, ...); + +vec3_t vec3_origin = {0,0,0}; +#ifdef USEFPM +vec3_FPM_t vec3_originFPM = {0,0,0}; +#endif +int nanmask = 255<<23; + +/*-----------------------------------------------------------------*/ + +#define DEG2RAD( a ) ( a * M_PI ) / 180.0F + +void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal ) +{ + float d; + vec3_t n; + float inv_denom; + + inv_denom = 1.0F / DotProduct( normal, normal ); + + d = DotProduct( normal, p ) * inv_denom; + + n[0] = normal[0] * inv_denom; + n[1] = normal[1] * inv_denom; + n[2] = normal[2] * inv_denom; + + dst[0] = p[0] - d * n[0]; + dst[1] = p[1] - d * n[1]; + dst[2] = p[2] - d * n[2]; +} + +#ifdef USEFPM +void ProjectPointOnPlaneFPM( vec3_FPM_t dst, const vec3_FPM_t p, const vec3_FPM_t normal ) +{ + fixedpoint_t d; + vec3_FPM_t n; + fixedpoint_t inv_denom; + + inv_denom = /*1.0F*/0x10000 / DotProductFPM( normal, normal ); + + d = DotProductFPM( normal, p ) * inv_denom; + + n[0] = FPM_MUL(normal[0], inv_denom); + n[1] = FPM_MUL(normal[1], inv_denom); + n[2] = FPM_MUL(normal[2], inv_denom); + + dst[0] = FPM_SUB(p[0], FPM_MUL(d, n[0])); + dst[1] = FPM_SUB(p[1], FPM_MUL(d, n[1])); + dst[2] = FPM_SUB(p[2], FPM_MUL(d, n[2])); +} +#endif + +/* +** assumes "src" is normalized +*/ +void PerpendicularVector( vec3_t dst, const vec3_t src ) +{ + int pos; + int i; + float minelem = 1.0F; + vec3_t tempvec; + + /* + ** find the smallest magnitude axially aligned vector + */ + for ( pos = 0, i = 0; i < 3; i++ ) + { + if ( fabs( src[i] ) < minelem ) + { + pos = i; + minelem = (float)fabs( src[i] ); + } + } + tempvec[0] = tempvec[1] = tempvec[2] = 0.0F; + tempvec[pos] = 1.0F; + + /* + ** project the point onto the plane defined by src + */ + ProjectPointOnPlane( dst, tempvec, src ); + + /* + ** normalize the result + */ + VectorNormalize( dst ); +} + +#ifdef USEFPM +void PerpendicularVectorFPM( vec3_FPM_t dst, const vec3_FPM_t src ) +{ + int pos; + int i; + fixedpoint_t minelem = 0x00010000; + vec3_FPM_t tempvec; + + /* + ** find the smallest magnitude axially aligned vector + */ + for ( pos = 0, i = 0; i < 3; i++ ) + { + if ( FPM_ABS( src[i] ) < minelem ) + { + pos = i; + minelem = FPM_ABS( src[i] ); + } + } + tempvec[0] = tempvec[1] = tempvec[2] = 0; + tempvec[pos] = 0x10000; + + /* + ** project the point onto the plane defined by src + */ + ProjectPointOnPlaneFPM( dst, tempvec, src ); + + /* + ** normalize the result + */ + VectorNormalizeFPM( dst ); +} +#endif + +#ifdef _WIN32 +#pragma optimize( "", off ) +#endif + + +void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ) +{ + float m[3][3]; + float im[3][3]; + float zrot[3][3]; + float tmpmat[3][3]; + float rot[3][3]; + int i; + vec3_t vr, vup, vf; + + vf[0] = dir[0]; + vf[1] = dir[1]; + vf[2] = dir[2]; + + PerpendicularVector( vr, dir ); + CrossProduct( vr, vf, vup ); + + m[0][0] = vr[0]; + m[1][0] = vr[1]; + m[2][0] = vr[2]; + + m[0][1] = vup[0]; + m[1][1] = vup[1]; + m[2][1] = vup[2]; + + m[0][2] = vf[0]; + m[1][2] = vf[1]; + m[2][2] = vf[2]; + + Q_memcpy( im, m, sizeof( im ) ); + + im[0][1] = m[1][0]; + im[0][2] = m[2][0]; + im[1][0] = m[0][1]; + im[1][2] = m[2][1]; + im[2][0] = m[0][2]; + im[2][1] = m[1][2]; + + Q_memset( zrot, 0, sizeof( zrot ) ); + zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F; + + zrot[0][0] = (float)cos( DEG2RAD( degrees ) ); + zrot[0][1] = (float)sin( DEG2RAD( degrees ) ); + zrot[1][0] = (float)-sin( DEG2RAD( degrees ) ); + zrot[1][1] = (float)cos( DEG2RAD( degrees ) ); + + R_ConcatRotations( m, zrot, tmpmat ); + R_ConcatRotations( tmpmat, im, rot ); + + for ( i = 0; i < 3; i++ ) + { + dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2]; + } +} + +#ifdef USEFPM +void RotatePointAroundVectorFPM( vec3_FPM_t dst, const vec3_FPM_t dir, const vec3_FPM_t point, fixedpoint_t degrees ) +{ + fixedpoint_t m[3][3]; + fixedpoint_t im[3][3]; + fixedpoint_t zrot[3][3]; + fixedpoint_t tmpmat[3][3]; + fixedpoint_t rot[3][3]; + int i; + vec3_FPM_t vr, vup, vf; + + vf[0] = dir[0]; + vf[1] = dir[1]; + vf[2] = dir[2]; + + PerpendicularVectorFPM( vr, dir ); + CrossProductFPM( vr, vf, vup ); + + m[0][0] = vr[0]; + m[1][0] = vr[1]; + m[2][0] = vr[2]; + + m[0][1] = vup[0]; + m[1][1] = vup[1]; + m[2][1] = vup[2]; + + m[0][2] = vf[0]; + m[1][2] = vf[1]; + m[2][2] = vf[2]; + + Q_memcpy( im, m, sizeof( im ) ); + + im[0][1] = m[1][0]; + im[0][2] = m[2][0]; + im[1][0] = m[0][1]; + im[1][2] = m[2][1]; + im[2][0] = m[0][2]; + im[2][1] = m[1][2]; + + Q_memset( zrot, 0, sizeof( zrot ) ); + zrot[0][0] = zrot[1][1] = zrot[2][2] = 0x10000; + + zrot[1][0]=-(zrot[0][0] = FPM_SIN_DEG(degrees)); + zrot[1][1] = FPM_COS_DEG( degrees ); + + R_ConcatRotationsFPM( m, zrot, tmpmat ); + R_ConcatRotationsFPM( tmpmat, im, rot ); + + for ( i = 0; i < 3; i++ ) + { + dst[i] = FPM_ADD3(FPM_MUL(rot[i][0], point[0]), FPM_MUL(rot[i][1], point[1]), FPM_MUL(rot[i][2], point[2])); + } +} +#endif + +#ifdef _WIN32 +#pragma optimize( "", on ) +#endif + +/*-----------------------------------------------------------------*/ + + +float anglemod(float a) +{ +#if 0 + if (a >= 0) + a -= 360*(int)(a/360); + else + a += 360*( 1 + (int)(-a/360) ); +#endif + a = (float)((360.0/65536) * ((int)(a*(65536/360.0)) & 65535)); + return a; +} + +#ifdef USEFPM +fixedpoint_t anglemodFPM(fixedpoint_t a) +{ +#if 0 + if (a >= 0) + a -= 360*(int)(a/360); + else + a += 360*( 1 + (int)(-a/360) ); +#endif + //Dan: TODO: the following will overflow 16.16 signed fixedpoint. This algorithm + //needs to be tweaked to work with fixedpoint without overflowing. + a = FPM_FROMFLOAT((float)((360.0/65536) * ((int)(FPM_TOFLOAT(a)*(65536/360.0)) & 65535))); + +// a = FPM_MUL(FPM_FROMFLOAT(360.0/65536), FPM_FROMLONG((FPM_TOLONG(FPM_MUL(a,FPM_FROMFLOAT(65536/360.0))) & 65535))); + return a; +} +#endif + +/* +================== +BOPS_Error + +Split out like this for ASM to call. +================== +*/ +void BOPS_Error (void) +{ + Sys_Error ("BoxOnPlaneSide: Bad signbits"); +} + + +#if !id386 + +/* +================== +BoxOnPlaneSide + +Returns 1, 2, or 1 + 2 +================== +*/ +int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, mplane_t *p) +{ + float dist1, dist2; + int sides; + +#if 0 // this is done by the BOX_ON_PLANE_SIDE macro before calling this + // function +// fast axial cases + if (p->type < 3) + { + if (p->dist <= emins[p->type]) + return 1; + if (p->dist >= emaxs[p->type]) + return 2; + return 3; + } +#endif + +// general case + switch (p->signbits) + { + case 0: +dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; + break; + case 1: +dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; +dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; + break; + case 2: +dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; + break; + case 3: +dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; +dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; + break; + case 4: +dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; + break; + case 5: +dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]; +dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]; + break; + case 6: +dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; + break; + case 7: +dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]; +dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]; + break; + default: + dist1 = dist2 = 0; // shut up compiler + BOPS_Error (); + break; + } + +#if 0 + int i; + vec3_t corners[2]; + + for (i=0 ; i<3 ; i++) + { + if (plane->normal[i] < 0) + { + corners[0][i] = emins[i]; + corners[1][i] = emaxs[i]; + } + else + { + corners[1][i] = emins[i]; + corners[0][i] = emaxs[i]; + } + } + dist = DotProduct (plane->normal, corners[0]) - plane->dist; + dist2 = DotProduct (plane->normal, corners[1]) - plane->dist; + sides = 0; + if (dist1 >= 0) + sides = 1; + if (dist2 < 0) + sides |= 2; + +#endif + + sides = 0; + if (dist1 >= p->dist) + sides = 1; + if (dist2 < p->dist) + sides |= 2; + +#ifdef PARANOID +if (sides == 0) + Sys_Error ("BoxOnPlaneSide: sides==0"); +#endif + + return sides; +} + +#ifdef USEFPM +int BoxOnPlaneSideFPM (vec3_FPM_t emins, vec3_FPM_t emaxs, mplane_FPM_t *p) +{ + fixedpoint_t dist1, dist2; + int sides; + +// general case + switch (p->signbits) + { + case 0: + dist1 = DotProductFPM(p->normal, emaxs); + dist2 = DotProductFPM(p->normal, emins); + break; + case 1: + dist1 = FPM_ADD3(FPM_MUL(p->normal[0],emins[0]),FPM_MUL(p->normal[1],emaxs[1]),FPM_MUL(p->normal[2],emaxs[2])); + dist2 = FPM_ADD3(FPM_MUL(p->normal[0],emaxs[0]),FPM_MUL(p->normal[1],emins[1]),FPM_MUL(p->normal[2],emins[2])); + break; + case 2: + dist1 = FPM_ADD3(FPM_MUL(p->normal[0],emaxs[0]),FPM_MUL(p->normal[1],emins[1]),FPM_MUL(p->normal[2],emaxs[2])); + dist2 = FPM_ADD3(FPM_MUL(p->normal[0],emins[0]),FPM_MUL(p->normal[1],emaxs[1]),FPM_MUL(p->normal[2],emins[2])); + break; + case 3: + dist1 = FPM_ADD3(FPM_MUL(p->normal[0],emins[0]),FPM_MUL(p->normal[1],emins[1]),FPM_MUL(p->normal[2],emaxs[2])); + dist2 = FPM_ADD3(FPM_MUL(p->normal[0],emaxs[0]),FPM_MUL(p->normal[1],emaxs[1]),FPM_MUL(p->normal[2],emins[2])); + break; + case 4: + dist1 = FPM_ADD3(FPM_MUL(p->normal[0],emaxs[0]),FPM_MUL(p->normal[1],emaxs[1]),FPM_MUL(p->normal[2],emins[2])); + dist2 = FPM_ADD3(FPM_MUL(p->normal[0],emins[0]),FPM_MUL(p->normal[1],emins[1]),FPM_MUL(p->normal[2],emaxs[2])); + break; + case 5: + dist1 = FPM_ADD3(FPM_MUL(p->normal[0],emins[0]),FPM_MUL(p->normal[1],emaxs[1]),FPM_MUL(p->normal[2],emins[2])); + dist2 = FPM_ADD3(FPM_MUL(p->normal[0],emaxs[0]),FPM_MUL(p->normal[1],emins[1]),FPM_MUL(p->normal[2],emaxs[2])); + break; + case 6: + dist1 = FPM_ADD3(FPM_MUL(p->normal[0],emaxs[0]),FPM_MUL(p->normal[1],emins[1]),FPM_MUL(p->normal[2],emins[2])); + dist2 = FPM_ADD3(FPM_MUL(p->normal[0],emins[0]),FPM_MUL(p->normal[1],emaxs[1]),FPM_MUL(p->normal[2],emaxs[2])); + break; + case 7: + dist1 = FPM_ADD3(FPM_MUL(p->normal[0],emins[0]),FPM_MUL(p->normal[1],emins[1]),FPM_MUL(p->normal[2],emins[2])); + dist2 = FPM_ADD3(FPM_MUL(p->normal[0],emaxs[0]),FPM_MUL(p->normal[1],emaxs[1]),FPM_MUL(p->normal[2],emaxs[2])); + break; + default: + dist1 = dist2 = 0; // shut up compiler + BOPS_Error (); + break; + } + + + sides = 0; + if (dist1 >= p->dist) + sides = 1; + if (dist2 < p->dist) + sides |= 2; + +#ifdef PARANOID + if (sides == 0) + Sys_Error ("BoxOnPlaneSide: sides==0"); +#endif + + return sides; +} +#endif +#endif + + +void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + angle = (float)(angles[YAW] * (M_PI*2 / 360)); + sy = (float)sin(angle); + cy = (float)cos(angle); + angle = (float)(angles[PITCH] * (M_PI*2 / 360)); + sp = (float)sin(angle); + cp = (float)cos(angle); + angle = (float)(angles[ROLL] * (M_PI*2 / 360)); + sr = (float)sin(angle); + cr = (float)cos(angle); + + forward[0] = cp*cy; + forward[1] = cp*sy; + forward[2] = -sp; + right[0] = (-1*sr*sp*cy+-1*cr*-sy); + right[1] = (-1*sr*sp*sy+-1*cr*cy); + right[2] = -1*sr*cp; + up[0] = (cr*sp*cy+-sr*-sy); + up[1] = (cr*sp*sy+-sr*cy); + up[2] = cr*cp; +} + +#ifdef USEFPM +void AngleVectorsFPM (vec3_FPM_t angles, vec3_FPM_t forward, vec3_FPM_t right, vec3_FPM_t up) +{ + double source; + double angle; +// fixedpoint_t angle; +// fixedpoint_t sr, sp, sy, cr, cp, cy; + __int64 sr, sp, sy, cr, cp, cy; + register __int64 /*conv, mul,*/ accum1, accum2, accum1b, accum2b; + + //Dan: ID converted all of these angles to rads for the sin, cos functions. + //My Fixed Point Math routines can calc trig based on degrees. So this routine + //is much more efficient than it was before + + source=FPM_TOFLOAT(FPM_MUL(angles[YAW], FPM_DIV(FPM_PI, FPM_FROMLONGC(180)))); + angle = sin(source); + sy = (__int64)(angle*(double)(2^32)); + + angle = cos(source); + cy = (__int64)(angle*(double)(2^32)); + +// sy = FPM_SIN_DEG(angles[YAW]); +// cy = FPM_COS_DEG(angles[YAW]); + + source=FPM_TOFLOAT(FPM_MUL(angles[PITCH], FPM_DIV(FPM_PI, FPM_FROMLONGC(180)))); + angle = sin(source); + sp = (__int64)(angle*(double)(2^32)); + + angle = cos(source); + cp = (__int64)(angle*(double)(2^32)); + +// angle = angles[PITCH] * (M_PI*2 / 360); +// sp = FPM_SIN_DEG(angles[PITCH]); +// cp = FPM_COS_DEG(angles[PITCH]); +// angle = angles[ROLL] * (M_PI*2 / 360); + + source=FPM_TOFLOAT(FPM_MUL(angles[ROLL], FPM_DIV(FPM_PI, FPM_FROMLONGC(180)))); + angle = sin(source); + sr = (__int64)(angle*(double)(2^32)); + + angle = cos(source); + cr = (__int64)(angle*(double)(2^32)); + +// sr = FPM_SIN_DEG(angles[ROLL]); +// cr = FPM_COS_DEG(angles[ROLL]); + + forward[0] = (fixedpoint_t)((cp*cy)>>32); //FPM_MUL(cp,cy); + forward[1] = (fixedpoint_t)((cp*sy)>>32); //FPM_MUL(cp,sy); + forward[2] = (fixedpoint_t)((-sp)>>16); + + accum1=-sr; + accum2=-sr; + + accum1*=sp; + accum2*=sp; + + accum1*=cy; + accum2b=cy; + + accum1b=-cr; + accum2b*=-cr; + + accum1b*=-sy; + accum2*=sy; + + accum1+=accum1b; + accum2+=accum2b; + accum1>>=16; + accum2>>=16; + right[0]=(fixedpoint_t)accum1; + right[1]=(fixedpoint_t)accum2; + + //right[0] = FPM_ADD(FPM_MUL(FPM_MUL(FPM_MUL(FPM_FROMLONG(-1),sr),sp),cy),FPM_MUL(FPM_MUL(FPM_FROMLONG(-1),cr),-sy)); + //right[0] = (-1*sr*sp*cy+-1*cr*-sy); + //right[1] = FPM_ADD(FPM_MUL(FPM_MUL(FPM_MUL(FPM_FROMLONG(-1),sr),sp),sy),FPM_MUL(FPM_MUL(FPM_FROMLONG(-1),cr),cy)); + //right[1] = (-1*sr*sp*sy+-1*cr*cy); + //right[2] = FPM_MUL(FPM_MUL(FPM_FROMLONG(-1),sr),cp); + accum1=-sr; + accum1*=cp; + accum1>>=16; + right[2]=(fixedpoint_t)accum1; + + accum1=cr; + accum1*=sp; + accum1*=cy; + accum1b=-sr; + accum1b*=-sy; + accum1+=accum1b; + accum1>>=16; + up[0] = (fixedpoint_t)accum1; + //right[2] = -1*sr*cp; + //up[0] = FPM_ADD(FPM_MUL(FPM_MUL(cr,sp),cy),FPM_MUL(-sr,-sy)); + //up[0] = (cr*sp*cy+-sr*-sy); + + accum1=cr; + accum1*=sp; + accum1*=sy; + accum1b=-sr; + accum1b*=cy; + accum1+=accum1b; + accum1>>=16; + up[1]=(fixedpoint_t)accum1; + + //up[1] = FPM_ADD(FPM_MUL(FPM_MUL(cr,sp),sy),FPM_MUL(-sr,cy)); + //up[1] = (cr*sp*sy+-sr*cy); + + accum1=cr; + accum1*=cp; + accum1>>=16; + up[2]=(fixedpoint_t)accum1; + + //up[2] = FPM_MUL(cr,cp); + //up[2] = cr*cp; +} +#endif + +int VectorCompare (vec3_t v1, vec3_t v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (v1[i] != v2[i]) + return 0; + + return 1; +} + +#ifdef USEFPM +int VectorCompareFPM (vec3_FPM_t v1, vec3_FPM_t v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (v1[i] != v2[i]) + return 0; + + return 1; +} +#endif + +void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc) +{ + vecc[0] = veca[0] + scale*vecb[0]; + vecc[1] = veca[1] + scale*vecb[1]; + vecc[2] = veca[2] + scale*vecb[2]; +} + +#ifdef USEFPM +void VectorMAFPM (vec3_FPM_t veca, fixedpoint_t scale, vec3_FPM_t vecb, vec3_FPM_t vecc) +{ + vecc[0] = FPM_ADD(veca[0], FPM_MUL(scale, vecb[0])); + vecc[1] = FPM_ADD(veca[1], FPM_MUL(scale, vecb[1])); + vecc[2] = FPM_ADD(veca[2], FPM_MUL(scale, vecb[2])); +} +#endif + +//Dan: The following functions do not appear to be used by WinQuake +/* +vec_t _DotProduct (vec3_t v1, vec3_t v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out) +{ + out[0] = veca[0]-vecb[0]; + out[1] = veca[1]-vecb[1]; + out[2] = veca[2]-vecb[2]; +} + +void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out) +{ + out[0] = veca[0]+vecb[0]; + out[1] = veca[1]+vecb[1]; + out[2] = veca[2]+vecb[2]; +} + +void _VectorCopy (vec3_t in, vec3_t out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} +*/ + +void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +#ifdef USEFPM +void CrossProductFPM (vec3_FPM_t v1, vec3_FPM_t v2, vec3_FPM_t cross) +{ + cross[0] = FPM_SUB(FPM_MUL(v1[1], v2[2]), FPM_MUL(v1[2], v2[1])); + cross[1] = FPM_SUB(FPM_MUL(v1[2], v2[0]), FPM_MUL(v1[0], v2[2])); + cross[2] = FPM_SUB(FPM_MUL(v1[0], v2[1]), FPM_MUL(v1[1], v2[0])); +} +#endif + +vec_t Length(vec3_t v) +{ + int i; + float length; + + length = 0; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = (float)sqrt (length); // FIXME + + return length; +} + +#ifdef USEFPM +fixedpoint_t LengthFPM(vec3_FPM_t v) +{ + int i; + //Dan: squaring the vectors results in overflow, so we're hardcoding 64 bit 16.16 fixedpoint: + __int64 length, tmp; + +// fixedpoint_t length; + + length = 0; + for (i=0 ; i< 3 ; i++) { + tmp=v[i]; + length += (tmp*tmp)>>16; + } + return (fixedpoint_t)sqrt (length/65536.0)*65536; // FIXME (not Dan's comment) + +// return length; +} +#endif + +float VectorNormalize (vec3_t v) +{ + float length, ilength; + + length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + length = (float)sqrt (length); // FIXME + + if (length) + { + ilength = 1/length; + v[0] *= ilength; + v[1] *= ilength; + v[2] *= ilength; + } + + return length; + +} + +#ifdef USEFPM +fixedpoint_t VectorNormalizeFPM (vec3_FPM_t v) +{ + fixedpoint_t length;//, ilength; + + length = FPM_ADD3(FPM_MUL(v[0],v[0]),FPM_MUL(v[1],v[1]),FPM_MUL(v[2],v[2])); + length = FPM_SQRT (length); // FIXME (not dan's comment) + + if (length) + { + //ilength = FPM_INV(length); + v[0]=FPM_DIV(v[0], length); //FPM_MUL(v[0], ilength); + v[1]=FPM_DIV(v[1], length); //FPM_MUL(v[1], ilength); + v[2]=FPM_DIV(v[2], length); //FPM_MUL(v[2], ilength); + } + + return length; + +} +#endif + +void VectorInverse (vec3_t v) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +#ifdef USEFPM +void VectorInverseFPM (vec3_FPM_t v) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} +#endif + +void VectorScale (vec3_t in, vec_t scale, vec3_t out) +{ + out[0] = in[0]*scale; + out[1] = in[1]*scale; + out[2] = in[2]*scale; +} + +#ifdef USEFPM +void VectorScaleFPM (vec3_FPM_t in, fixedpoint_t scale, vec3_FPM_t out) +{ + out[0] = FPM_MUL(in[0], scale); + out[1] = FPM_MUL(in[1], scale); + out[2] = FPM_MUL(in[2], scale); +} +#endif + +int Q_log2(int val) +{ + int answer=0; + while (val>>=1) + answer++; + return answer; +} + + +/* +================ +R_ConcatRotations +================ +*/ +void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]) +{ + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + + in1[0][2] * in2[2][2]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + + in1[1][2] * in2[2][2]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + + in1[2][2] * in2[2][2]; +} + +#ifdef USEFPM +void R_ConcatRotationsFPM (fixedpoint_t in1[3][3], fixedpoint_t in2[3][3], fixedpoint_t out[3][3]) +{ + out[0][0] = FPM_ADD3(FPM_MUL(in1[0][0],in2[0][0]), FPM_MUL(in1[0][1],in2[1][0]), + FPM_MUL(in1[0][2],in2[2][0])); + out[0][1] = FPM_ADD3(FPM_MUL(in1[0][0],in2[0][1]), FPM_MUL(in1[0][1],in2[1][1]), + FPM_MUL(in1[0][2],in2[2][1])); + out[0][2] = FPM_ADD3(FPM_MUL(in1[0][0],in2[0][2]), FPM_MUL(in1[0][1],in2[1][2]), + FPM_MUL(in1[0][2],in2[2][2])); + out[1][0] = FPM_ADD3(FPM_MUL(in1[1][0],in2[0][0]), FPM_MUL(in1[1][1],in2[1][0]), + FPM_MUL(in1[1][2],in2[2][0])); + out[1][1] = FPM_ADD3(FPM_MUL(in1[1][0],in2[0][1]), FPM_MUL(in1[1][1],in2[1][1]), + FPM_MUL(in1[1][2],in2[2][1])); + out[1][2] = FPM_ADD3(FPM_MUL(in1[1][0],in2[0][2]), FPM_MUL(in1[1][1],in2[1][2]), + FPM_MUL(in1[1][2],in2[2][2])); + out[2][0] = FPM_ADD3(FPM_MUL(in1[2][0],in2[0][0]), FPM_MUL(in1[2][1],in2[1][0]), + FPM_MUL(in1[2][2],in2[2][0])); + out[2][1] = FPM_ADD3(FPM_MUL(in1[2][0],in2[0][1]), FPM_MUL(in1[2][1],in2[1][1]), + FPM_MUL(in1[2][2],in2[2][1])); + out[2][2] = FPM_ADD3(FPM_MUL(in1[2][0],in2[0][2]), FPM_MUL(in1[2][1],in2[1][2]), + FPM_MUL(in1[2][2],in2[2][2])); +} +#endif + +/* +================ +R_ConcatTransforms +================ +*/ +void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]) +{ + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + + in1[0][2] * in2[2][2]; + out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + + in1[0][2] * in2[2][3] + in1[0][3]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + + in1[1][2] * in2[2][2]; + out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + + in1[1][2] * in2[2][3] + in1[1][3]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + + in1[2][2] * in2[2][2]; + out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + + in1[2][2] * in2[2][3] + in1[2][3]; +} + +#ifdef USEFPM +void R_ConcatTransformsFPM (fixedpoint_t in1[3][4], fixedpoint_t in2[3][4], fixedpoint_t out[3][4]) +{ + register __int64 accum, mul; + int i; + for (i=0; i<3; i++) { + accum=in1[i][0]; + accum*=in2[0][0]; + mul=in1[i][1]; + mul*=in2[1][0]; + accum+=mul; + mul=in1[i][2]; + mul*=in2[2][0]; + accum+=mul; + accum>>=16; + out[i][0]=(fixedpoint_t)accum; + + accum=in1[i][0]; + accum*=in2[0][1]; + mul=in1[i][1]; + mul*=in2[1][1]; + accum+=mul; + mul=in1[i][2]; + mul*=in2[2][1]; + accum+=mul; + accum>>=16; + out[i][1]=(fixedpoint_t)accum; + + accum=in1[i][0]; + accum*=in2[0][2]; + mul=in1[i][1]; + mul*=in2[1][2]; + accum+=mul; + mul=in1[i][2]; + mul*=in2[2][2]; + accum+=mul; + accum>>=16; + out[i][2]=(fixedpoint_t)accum; + + accum=in1[i][0]; + accum*=in2[0][3]; + mul=in1[i][1]; + mul*=in2[1][3]; + accum+=mul; + mul=in1[i][2]; + mul*=in2[2][3]; + accum+=mul; + mul=in1[0][3]; + mul<<=16; //16.16 -> 32.32 + accum+=mul; + accum>>=16; + out[i][3]=(fixedpoint_t)accum; + } +} +#endif + +/* +void R_ConcatTransformsFPM (fixedpoint_t in1[3][4], fixedpoint_t in2[3][4], fixedpoint_t out[3][4]) +{ + out[0][0] = FPM_ADD3(FPM_MUL(in1[0][0],in2[0][0]),FPM_MUL(in1[0][1],in2[1][0]), + FPM_MUL(in1[0][2],in2[2][0])); + out[0][1] = FPM_ADD3(FPM_MUL(in1[0][0],in2[0][1]),FPM_MUL(in1[0][1],in2[1][1]), + FPM_MUL(in1[0][2],in2[2][1])); + out[0][2] = FPM_ADD3(FPM_MUL(in1[0][0],in2[0][2]),FPM_MUL(in1[0][1],in2[1][2]), + FPM_MUL(in1[0][2],in2[2][2])); + out[0][3] = FPM_ADD(FPM_ADD3(FPM_MUL(in1[0][0],in2[0][3]),FPM_MUL(in1[0][1],in2[1][3]), + FPM_MUL(in1[0][2],in2[2][3])),in1[0][3]); + out[1][0] = FPM_ADD3(FPM_MUL(in1[1][0],in2[0][0]),FPM_MUL(in1[1][1],in2[1][0]), + FPM_MUL(in1[1][2],in2[2][0])); + out[1][1] = FPM_ADD3(FPM_MUL(in1[1][0],in2[0][1]),FPM_MUL(in1[1][1],in2[1][1]), + FPM_MUL(in1[1][2],in2[2][1])); + out[1][2] = FPM_ADD3(FPM_MUL(in1[1][0],in2[0][2]),FPM_MUL(in1[1][1],in2[1][2]), + FPM_MUL(in1[1][2],in2[2][2])); + out[1][3] = FPM_ADD(FPM_ADD3(FPM_MUL(in1[1][0],in2[0][3]),FPM_MUL(in1[1][1],in2[1][3]), + FPM_MUL(in1[1][2],in2[2][3])),in1[1][3]); + out[2][0] = FPM_ADD3(FPM_MUL(in1[2][0],in2[0][0]),FPM_MUL(in1[2][1],in2[1][0]), + FPM_MUL(in1[2][2],in2[2][0])); + out[2][1] = FPM_ADD3(FPM_MUL(in1[2][0],in2[0][1]),FPM_MUL(in1[2][1],in2[1][1]), + FPM_MUL(in1[2][2],in2[2][1])); + out[2][2] = FPM_ADD3(FPM_MUL(in1[2][0],in2[0][2]),FPM_MUL(in1[2][1],in2[1][2]), + FPM_MUL(in1[2][2],in2[2][2])); + out[2][3] = FPM_ADD(FPM_ADD3(FPM_MUL(in1[2][0],in2[0][3]),FPM_MUL(in1[2][1],in2[1][3]), + FPM_MUL(in1[2][2],in2[2][3])),in1[2][3]); +} +*/ + +#ifdef USEFPM +void R_ConcatTransforms8_24FPM (fixedpoint_t in1[3][4], fixedpoint_t in2[3][4], fixedpoint8_24_t out[3][4]) +{ + int i; + register __int64 accum, i1, i2, i3, conv; + + for (i=0; i<3; i++) { + accum=0; + i1=in1[i][0]; + i1<<=16; + i2=in1[i][1]; + i2<<=16; + i3=in1[i][2]; + i3<<=16; + + conv=in2[0][0]; + conv<<=16; + conv*=i1; + accum=conv>>16; + conv=in2[1][0]; + conv<<=16; + conv*=i2; + accum+=conv>>16; + conv=in2[2][0]; + conv<<=16; + conv*=i3; + accum+=conv>>16; + out[i][0] = (fixedpoint8_24_t)accum>>8; + + conv=in2[0][1]; + conv<<=16; + conv*=i1; + accum=conv>>16; + conv=in2[1][1]; + conv<<=16; + conv*=i2; + accum+=conv>>16; + conv=in2[2][1]; + conv<<=16; + conv*=i3; + accum+=conv>>16; + out[i][1] = (fixedpoint8_24_t)accum>>8; + + conv=in2[0][2]; + conv<<=16; + conv*=i1; + accum=conv>>16; + conv=in2[1][2]; + conv<<=16; + conv*=i2; + accum+=conv>>16; + conv=in2[2][2]; + conv<<=16; + conv*=i3; + accum+=conv>>16; + out[i][2] = (fixedpoint8_24_t)accum>>8; //to 8.24 + + conv=in2[0][3]; + conv<<=16; + conv*=i1; + accum=conv>>16; + conv=in2[1][3]; + conv<<=16; + conv*=i2; + accum+=conv>>16; + conv=in2[2][3]; + conv<<=16; + conv*=i3; + accum+=conv>>16; + conv=in1[0][3]; + conv<<=16; + accum+=conv; + out[i][3] = (fixedpoint8_24_t)accum>>16; //to 16.16 + } +} +#endif + +/* +void R_ConcatTransforms8_24FPM (fixedpoint_t in1[3][4], fixedpoint_t in2[3][4], fixedpoint8_24_t out[3][4]) +{ + out[0][0] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[0][0],in2[0][0]),FPM_MUL(in1[0][1],in2[1][0]), + FPM_MUL(in1[0][2],in2[2][0]))); + out[0][1] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[0][0],in2[0][1]),FPM_MUL(in1[0][1],in2[1][1]), + FPM_MUL(in1[0][2],in2[2][1]))); + out[0][2] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[0][0],in2[0][2]),FPM_MUL(in1[0][1],in2[1][2]), + FPM_MUL(in1[0][2],in2[2][2]))); + out[0][3] = (fixedpoint_t)FPM_ADD(FPM_ADD3(FPM_MUL(in1[0][0],in2[0][3]),FPM_MUL(in1[0][1],in2[1][3]), + FPM_MUL(in1[0][2],in2[2][3])),in1[0][3]); + out[1][0] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[1][0],in2[0][0]),FPM_MUL(in1[1][1],in2[1][0]), + FPM_MUL(in1[1][2],in2[2][0]))); + out[1][1] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[1][0],in2[0][1]),FPM_MUL(in1[1][1],in2[1][1]), + FPM_MUL(in1[1][2],in2[2][1]))); + out[1][2] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[1][0],in2[0][2]),FPM_MUL(in1[1][1],in2[1][2]), + FPM_MUL(in1[1][2],in2[2][2]))); + out[1][3] = (fixedpoint_t)FPM_ADD(FPM_ADD3(FPM_MUL(in1[1][0],in2[0][3]),FPM_MUL(in1[1][1],in2[1][3]), + FPM_MUL(in1[1][2],in2[2][3])),in1[1][3]); + out[2][0] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[2][0],in2[0][0]),FPM_MUL(in1[2][1],in2[1][0]), + FPM_MUL(in1[2][2],in2[2][0]))); + out[2][1] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[2][0],in2[0][1]),FPM_MUL(in1[2][1],in2[1][1]), + FPM_MUL(in1[2][2],in2[2][1]))); + out[2][2] = fpm_FromFixedPoint(FPM_ADD3(FPM_MUL(in1[2][0],in2[0][2]),FPM_MUL(in1[2][1],in2[1][2]), + FPM_MUL(in1[2][2],in2[2][2]))); + out[2][3] = (fixedpoint_t)FPM_ADD(FPM_ADD3(FPM_MUL(in1[2][0],in2[0][3]),FPM_MUL(in1[2][1],in2[1][3]), + FPM_MUL(in1[2][2],in2[2][3])),in1[2][3]); +} +*/ + +/* +=================== +FloorDivMod + +Returns mathematically correct (floor-based) quotient and remainder for +numer and denom, both of which should contain no fractional part. The +quotient must fit in 32 bits. +==================== +*/ + +void FloorDivMod (double numer, double denom, int *quotient, + int *rem) +{ + int q, r; + double x; + +#ifndef PARANOID + if (denom <= 0.0) + Sys_Error ("FloorDivMod: bad denominator %d\n", denom); + +// if ((floor(numer) != numer) || (floor(denom) != denom)) +// Sys_Error ("FloorDivMod: non-integer numer or denom %f %f\n", +// numer, denom); +#endif + + if (numer >= 0.0) + { + + x = floor(numer / denom); + q = (int)x; + r = (int)floor(numer - (x * denom)); + } + else + { + // + // perform operations with positive values, and fix mod to make floor-based + // + x = floor(-numer / denom); + q = -(int)x; + r = (int)floor(-numer - (x * denom)); + if (r != 0) + { + q--; + r = (int)denom - r; + } + } + + *quotient = q; + *rem = r; +} + + +/* +=================== +GreatestCommonDivisor +==================== +*/ +int GreatestCommonDivisor (int i1, int i2) +{ + if (i1 > i2) + { + if (i2 == 0) + return (i1); + return GreatestCommonDivisor (i2, i1 % i2); + } + else + { + if (i1 == 0) + return (i2); + return GreatestCommonDivisor (i1, i2 % i1); + } +} + + +#if !id386 + +// TODO: move to nonintel.c + +/* +=================== +Invert24To16 + +Inverts an 8.24 value to a 16.16 value +==================== +*/ + +fixed16_t Invert24To16(fixed16_t val) +{ + if (val < 256) + return (0xFFFFFFFF); + + return (fixed16_t) + (((double)0x10000 * (double)0x1000000 / (double)val) + 0.5); +} + +int ParseFloats(char *s, float *f, int *f_size) { + int i, argc; + + if (!s || !f || !f_size) + Sys_Error("ParseFloats() wrong params"); + + if (f_size[0] <= 0) + return (f_size[0] = 0); + + Cmd_TokenizeString(s); + // argc = min(Cmd_Argc(), f_size[0]); + argc = (Cmd_Argc(), f_size[0]); + + for(i = 0; i < argc; i++) + f[i] = Q_atof(Cmd_Argv(i)); + + for( ; i < f_size[0]; i++) + f[i] = 0; + + return (f_size[0] = argc); +} + +#endif diff --git a/project/jni/application/quake/source/mathlib.h b/project/jni/application/quake/source/mathlib.h new file mode 100644 index 000000000..2eafd5286 --- /dev/null +++ b/project/jni/application/quake/source/mathlib.h @@ -0,0 +1,146 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// mathlib.h + +#ifndef __MATHLIB_H__ +#define __MATHLIB_H__ + +//Dan East: +#include "FixedPointMath.h" + +#ifdef USE_PQ_OPT +typedef int fpvec3[3]; +#endif + +typedef fixedpoint_t vec3_FPM_t[3]; +typedef fixedpoint8_24_t vec3_8_24FPM_t[3]; +typedef fixedpoint_t vec5_FPM_t[5]; + +//End Dan + +typedef float vec_t; +typedef vec_t vec3_t[3]; +typedef vec_t vec5_t[5]; + +typedef int fixed4_t; +typedef int fixed8_t; +typedef int fixed16_t; + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +//struct mplane_s; + +extern vec3_t vec3_origin; +extern vec3_FPM_t vec3_originFPM; +extern int nanmask; + +#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) + +//Dan East: +#define DotProductFPM(x,y) FPM_ADD3(FPM_MUL(x[0],y[0]),FPM_MUL(x[1],y[1]),FPM_MUL(x[2],y[2])) +#define DotProduct8_24FPM(x,y) fpm_Add3(fpm_MulMixed8_24(x[0],y[0]),fpm_MulMixed8_24(x[1],y[1]),fpm_MulMixed8_24(x[2],y[2])) +#define VectorSubtractFPM(a,b,c) {c[0]=FPM_SUB(a[0],b[0]);c[1]=FPM_SUB(a[1],b[1]);c[2]=FPM_SUB(a[2],b[2]);} +#define VectorAddFPM(a,b,c) {c[0]=FPM_ADD(a[0],b[0]);c[1]=FPM_ADD(a[1],b[1]);c[2]=FPM_ADD(a[2],b[2]);} + +//Int the following two macros b represents the destination (following ID's convention) +#define VectorToFPM(a,b) {b[0]=FPM_FROMFLOAT(a[0]);b[1]=FPM_FROMFLOAT(a[1]);b[2]=FPM_FROMFLOAT(a[2]);} +#define FPMToVector(a,b) {b[0]=FPM_TOFLOAT(a[0]);b[1]=FPM_TOFLOAT(a[1]);b[2]=FPM_TOFLOAT(a[2]);} + +//End Dan + + +#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) +#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];} +#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];} +//Dan: Can't this be done with memcpy? +#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];} + +void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc); +void VectorMAFPM (vec3_FPM_t veca, fixedpoint_t scale, vec3_FPM_t vecb, vec3_FPM_t vecc); + + +int VectorCompare (vec3_t v1, vec3_t v2); +vec_t Length (vec3_t v); +fixedpoint_t LengthFPM (vec3_FPM_t v); +void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross); +void CrossProductFPM (vec3_FPM_t v1, vec3_FPM_t v2, vec3_FPM_t cross); +float VectorNormalize (vec3_t v); // returns vector length +fixedpoint_t VectorNormalizeFPM (vec3_FPM_t v); // returns vector length +void VectorInverse (vec3_t v); +void VectorInverseFPM (vec3_FPM_t v); +void VectorScale (vec3_t in, vec_t scale, vec3_t out); +void VectorScaleFPM (vec3_FPM_t in, fixedpoint_t scale, vec3_FPM_t out); +int Q_log2(int val); + +void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]); +void R_ConcatRotationsFPM (fixedpoint_t in1[3][3], fixedpoint_t in2[3][3], fixedpoint_t out[3][3]); +void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); +void R_ConcatTransformsFPM (fixedpoint_t in1[3][4], fixedpoint_t in2[3][4], fixedpoint_t out[3][4]); +void R_ConcatTransforms8_24FPM (fixedpoint_t in1[3][4], fixedpoint_t in2[3][4], fixedpoint8_24_t out[3][4]); + +void FloorDivMod (double numer, double denom, int *quotient, + int *rem); +fixed16_t Invert24To16(fixed16_t val); +int GreatestCommonDivisor (int i1, int i2); + +void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +void AngleVectorsFPM (vec3_FPM_t angles, vec3_FPM_t forward, vec3_FPM_t right, vec3_FPM_t up); +//int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct mplane_s *plane); +//int BoxOnPlaneSideFPM (vec3_FPM_t emins, vec3_FPM_t emaxs, struct mplane_FPM_s *plane); +float anglemod(float a); +fixedpoint_t anglemodFPM(fixedpoint_t a); + +#define BOX_ON_PLANE_SIDE(emins, emaxs, p) \ + (((p)->type < 3)? \ + ( \ + ((p)->dist <= (emins)[(p)->type])? \ + 1 \ + : \ + ( \ + ((p)->dist >= (emaxs)[(p)->type])?\ + 2 \ + : \ + 3 \ + ) \ + ) \ + : \ + BoxOnPlaneSide( (emins), (emaxs), (p))) + +#define BOX_ON_PLANE_SIDE_FPM(emins, emaxs, p) \ + (((p)->type < 3)? \ + ( \ + ((p)->dist <= (emins)[(p)->type])? \ + 1 \ + : \ + ( \ + ((p)->dist >= (emaxs)[(p)->type])?\ + 2 \ + : \ + 3 \ + ) \ + ) \ + : \ + BoxOnPlaneSideFPM( (emins), (emaxs), (p))) + +int ParseFloats(char *s, float *f, int *f_size); + +#endif // _MATHLIB_H_ diff --git a/project/jni/application/quake/source/menu.c b/project/jni/application/quake/source/menu.c new file mode 100644 index 000000000..a82882a8e --- /dev/null +++ b/project/jni/application/quake/source/menu.c @@ -0,0 +1,3496 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "quakedef.h" + +#ifdef _WIN32 +#include "winquake.h" +#endif + +//Dan East: +extern int min_vid_width; + +void (*vid_menudrawfn)(void); +void (*vid_menukeyfn)(int key); + +enum {m_none, m_main, m_singleplayer, m_load, m_save, m_multiplayer, m_setup, m_namemaker, m_net, m_options, m_video, m_keys, m_help, m_quit, m_serialconfig, m_modemconfig, m_lanconfig, m_gameoptions, m_search, m_slist} m_state; + +void M_Menu_Main_f (void); + void M_Menu_SinglePlayer_f (void); + void M_Menu_Load_f (void); + void M_Menu_Save_f (void); + void M_Menu_MultiPlayer_f (void); + void M_Menu_Setup_f (void); + void M_Menu_NameMaker_f (void); + void M_Menu_Net_f (void); + void M_Menu_Options_f (void); + void M_Menu_Keys_f (void); + void M_Menu_Video_f (void); + void M_Menu_Help_f (void); + void M_Menu_Quit_f (void); +void M_Menu_SerialConfig_f (void); + void M_Menu_ModemConfig_f (void); +void M_Menu_LanConfig_f (void); +void M_Menu_GameOptions_f (void); +void M_Menu_Search_f (void); +void M_Menu_ServerList_f (void); + +void M_Main_Draw (void); + void M_SinglePlayer_Draw (void); + void M_Load_Draw (void); + void M_Save_Draw (void); + void M_MultiPlayer_Draw (void); + void M_Setup_Draw (void); + void M_NameMaker_Draw (void); + void M_Net_Draw (void); + void M_Options_Draw (void); + void M_Keys_Draw (void); + void M_Video_Draw (void); + void M_Help_Draw (void); + void M_Quit_Draw (void); +void M_SerialConfig_Draw (void); + void M_ModemConfig_Draw (void); +void M_LanConfig_Draw (void); +void M_GameOptions_Draw (void); +void M_Search_Draw (void); +void M_ServerList_Draw (void); + +void M_Main_Key (int key); + void M_SinglePlayer_Key (int key); + void M_Load_Key (int key); + void M_Save_Key (int key); + void M_MultiPlayer_Key (int key); + void M_Setup_Key (int key); + void M_NameMaker_Key (int key); + void M_Net_Key (int key); + void M_Options_Key (int key); + void M_Keys_Key (int key); + void M_Video_Key (int key); + void M_Help_Key (int key); + void M_Quit_Key (int key); +void M_SerialConfig_Key (int key); + void M_ModemConfig_Key (int key); +void M_LanConfig_Key (int key); +void M_GameOptions_Key (int key); +void M_Search_Key (int key); +void M_ServerList_Key (int key); + +qboolean m_entersound; // play after drawing a frame, so caching + // won't disrupt the sound +qboolean m_recursiveDraw; + +int m_return_state; +qboolean m_return_onerror; +char m_return_reason [32]; + +#define StartingGame (m_multiplayer_cursor == 2) +#define JoiningGame (m_multiplayer_cursor == 1) +#define SerialConfig (m_net_cursor == 0) +#define DirectConfig (m_net_cursor == 1) +#define IPXConfig (m_net_cursor == 2) +#define TCPIPConfig (m_net_cursor == 3) + +void M_ConfigureNetSubsystem(void); + +/* +================ +M_DrawCharacter + +Draws one solid graphics character +================ +*/ +void M_DrawCharacter (int cx, int line, int num) +{ + Draw_Character ( cx + ((vid.width - /*320*/min_vid_width)>>1), line, num); +} + +void M_Print (int cx, int cy, char *str) +{ + //Dan: + if (str) + while (*str) + { + M_DrawCharacter (cx, cy, (*str)+128); + str++; + cx += 8; + } +} + +void M_PrintWhite (int cx, int cy, char *str) +{ + while (*str) + { + M_DrawCharacter (cx, cy, *str); + str++; + cx += 8; + } +} + +void M_DrawTransPic (int x, int y, qpic_t *pic) +{ + Draw_TransPic (x + ((vid.width - min_vid_width/*320*/)>>1), y, pic); +} + +void M_DrawPic (int x, int y, qpic_t *pic) +{ + Draw_Pic (x + ((vid.width - min_vid_width/*320*/)>>1), y, pic); +} + +byte identityTable[256]; +byte translationTable[256]; + +void M_BuildTranslationTable(int top, int bottom) +{ + int j; + byte *dest, *source; + + for (j = 0; j < 256; j++) + identityTable[j] = j; + dest = translationTable; + source = identityTable; + Q_memcpy (dest, source, 256); + + if (top < 128) // the artists made some backwards ranges. sigh. + Q_memcpy (dest + TOP_RANGE, source + top, 16); + else + for (j=0 ; j<16 ; j++) + dest[TOP_RANGE+j] = source[top+15-j]; + + if (bottom < 128) + Q_memcpy (dest + BOTTOM_RANGE, source + bottom, 16); + else + for (j=0 ; j<16 ; j++) + dest[BOTTOM_RANGE+j] = source[bottom+15-j]; +} + + +void M_DrawTransPicTranslate (int x, int y, qpic_t *pic) +{ + Draw_TransPicTranslate (x + ((vid.width - min_vid_width/*320*/)>>1), y, pic, translationTable); +} + + +void M_DrawTextBox (int x, int y, int width, int lines) +{ + qpic_t *p; + int cx, cy; + int n; + + // draw left side + cx = x; + cy = y; + p = Draw_CachePic ("gfx/box_tl.lmp"); + M_DrawTransPic (cx, cy, p); + p = Draw_CachePic ("gfx/box_ml.lmp"); + for (n = 0; n < lines; n++) + { + cy += 8; + M_DrawTransPic (cx, cy, p); + } + p = Draw_CachePic ("gfx/box_bl.lmp"); + M_DrawTransPic (cx, cy+8, p); + + // draw middle + cx += 8; + while (width > 0) + { + cy = y; + p = Draw_CachePic ("gfx/box_tm.lmp"); + M_DrawTransPic (cx, cy, p); + p = Draw_CachePic ("gfx/box_mm.lmp"); + for (n = 0; n < lines; n++) + { + cy += 8; + if (n == 1) + p = Draw_CachePic ("gfx/box_mm2.lmp"); + M_DrawTransPic (cx, cy, p); + } + p = Draw_CachePic ("gfx/box_bm.lmp"); + M_DrawTransPic (cx, cy+8, p); + width -= 2; + cx += 16; + } + + // draw right side + cy = y; + p = Draw_CachePic ("gfx/box_tr.lmp"); + M_DrawTransPic (cx, cy, p); + p = Draw_CachePic ("gfx/box_mr.lmp"); + for (n = 0; n < lines; n++) + { + cy += 8; + M_DrawTransPic (cx, cy, p); + } + p = Draw_CachePic ("gfx/box_br.lmp"); + M_DrawTransPic (cx, cy+8, p); +} + +//============================================================================= + +int m_save_demonum; + +/* +================ +M_ToggleMenu_f +================ +*/ +void M_ToggleMenu_f (void) { + m_entersound = true; + + if (key_dest == key_menu) { + if (m_state != m_main) { + M_Menu_Main_f (); + return; + } + + key_dest = key_game; + m_state = m_none; + return; + } + + if (key_dest == key_console) { + Con_ToggleConsole_f (); + } else { + M_Menu_Main_f (); + } +} + +//============================================================================= +/* MAIN MENU */ + +int m_main_cursor; +#define MAIN_ITEMS 5 + + +void M_Menu_Main_f (void) { + if (key_dest != key_menu) + { + m_save_demonum = cls.demonum; + cls.demonum = -1; + } + key_dest = key_menu; + m_state = m_main; + m_entersound = true; +} + +void M_Main_Draw (void) +{ + int f; + qpic_t *p; +/* +// M_DrawTransPic (0, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/ttl_main.lmp"); + M_DrawPic ( (min_vid_width-p->width)/2, 4, p); + M_DrawTransPic (18, 32, Draw_CachePic ("gfx/mainmenu.lmp") ); //56 + + f = (int)(host_time * 10)%6; + //38 + M_DrawTransPic (0, 32 + m_main_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) ); +*/ + M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/ttl_main.lmp"); + M_DrawPic ( (min_vid_width-p->width)/2, 4, p); + M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mainmenu.lmp") ); + + f = (int)(host_time * 10)%6; + + M_DrawTransPic (54, 32 + m_main_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) ); + +} + + +void M_Main_Key (int key) +{ + switch (key) + { + case K_ESCAPE: + case K_ALT: + key_dest = key_game; + m_state = m_none; + cls.demonum = m_save_demonum; + if (cls.demonum != -1 && !cls.demoplayback && cls.state != ca_connected) + CL_NextDemo (); + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + if (++m_main_cursor >= MAIN_ITEMS) + m_main_cursor = 0; + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + if (--m_main_cursor < 0) + m_main_cursor = MAIN_ITEMS - 1; + break; + + case K_CTRL: + case K_MOUSE1: + m_entersound = true; + + switch (m_main_cursor) + { + case 0: + M_Menu_SinglePlayer_f (); + break; + + case 1: + M_Menu_MultiPlayer_f (); + break; + + case 2: + M_Menu_Options_f (); + break; + + case 3: + M_Menu_Help_f (); + break; + + case 4: + M_Menu_Quit_f (); + break; + } + } +} + +//============================================================================= +/* SINGLE PLAYER MENU */ + +int m_singleplayer_cursor; +#define SINGLEPLAYER_ITEMS 3 + + +void M_Menu_SinglePlayer_f (void) +{ + key_dest = key_menu; + m_state = m_singleplayer; + m_entersound = true; +} + + +void M_SinglePlayer_Draw (void) +{ + int f; + qpic_t *p; + + M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/ttl_sgl.lmp"); + M_DrawPic ( (min_vid_width/*320*/-p->width)/2, 4, p); + M_DrawTransPic (72, 32, Draw_CachePic ("gfx/sp_menu.lmp") ); + + f = (int)(host_time * 10)%6; + + M_DrawTransPic (54, 32 + m_singleplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) ); +} + + +void M_SinglePlayer_Key (int key) +{ + switch (key) + { + case K_ESCAPE: + case K_ALT: + M_Menu_Main_f (); + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + if (++m_singleplayer_cursor >= SINGLEPLAYER_ITEMS) + m_singleplayer_cursor = 0; + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + if (--m_singleplayer_cursor < 0) + m_singleplayer_cursor = SINGLEPLAYER_ITEMS - 1; + break; + + case K_MOUSE1: + case K_CTRL: + m_entersound = true; + + switch (m_singleplayer_cursor) + { + case 0: + if (sv.active) + if (!SCR_ModalMessage("Are you sure you want to\nstart a new game?\n")) + break; + key_dest = key_game; + if (sv.active) + Cbuf_AddText ("disconnect\n"); + Cbuf_AddText ("maxplayers 1\n"); + Cbuf_AddText ("map start\n"); + break; + + case 1: + M_Menu_Load_f (); + break; + + case 2: + M_Menu_Save_f (); + break; + } + } +} + +//============================================================================= +/* LOAD/SAVE MENU */ + +int load_cursor; // 0 < load_cursor < MAX_SAVEGAMES + +#define MAX_SAVEGAMES 12 +char m_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH+1]; +int loadable[MAX_SAVEGAMES]; + +void M_ScanSaves (void) +{ + int i, j; + // char name[MAX_OSPATH]; + FILE *f; + int version; + unsigned long dummy,fsize; + char name[45]; + char *line; + + + for (i=0 ; iwidth)/2, 4, p); + + for (i=0 ; i< MAX_SAVEGAMES; i++) + M_Print (16, 32 + 8*i, m_filenames[i]); + +// line cursor + M_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1)); +} + + +void M_Save_Draw (void) +{ + int i; + qpic_t *p; + + p = Draw_CachePic ("gfx/p_save.lmp"); + M_DrawPic ( (/*320*/min_vid_width-p->width)/2, 4, p); + + for (i=0 ; i= MAX_SAVEGAMES) + load_cursor = 0; + break; + } +} + + +void M_Save_Key (int k) +{ + switch (k) + { + case K_ESCAPE: + case K_ALT: + M_Menu_SinglePlayer_f (); + break; + + case K_MOUSE1: + case K_CTRL: + m_state = m_none; + key_dest = key_game; + Cbuf_AddText (va("save s%i\n", load_cursor)); + return; + + case K_UPARROW: + case K_LEFTARROW: + S_LocalSound ("misc/menu1.wav"); + load_cursor--; + if (load_cursor < 0) + load_cursor = MAX_SAVEGAMES-1; + break; + + case K_DOWNARROW: + case K_RIGHTARROW: + S_LocalSound ("misc/menu1.wav"); + load_cursor++; + if (load_cursor >= MAX_SAVEGAMES) + load_cursor = 0; + break; + } +} + +//============================================================================= +/* MULTIPLAYER MENU */ + +int m_multiplayer_cursor; +#define MULTIPLAYER_ITEMS 4 + +void M_Menu_MultiPlayer_f (void) { + key_dest = key_menu; + m_state = m_multiplayer; + m_entersound = true; +} + +void M_MultiPlayer_Draw (void) { + int f; + qpic_t *p; + + M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/p_multi.lmp"); + M_DrawPic ( (/*320*/min_vid_width-p->width)/2, 4, p); + M_DrawTransPic (72, 32, Draw_CachePic ("gfx/mp_menu.lmp") ); + + f = (int)(host_time * 10)%6; + + M_DrawTransPic (54, 32 + m_multiplayer_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) ); + + if (serialAvailable || ipxAvailable || tcpipAvailable) + return; + M_PrintWhite ((/*320*/min_vid_width/2) - ((27*8)/2), 148, "No Communications Available"); +} + + +void M_MultiPlayer_Key (int key) { + switch (key) { + case K_ESCAPE: + case K_ALT: + M_Menu_Main_f (); + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + if (++m_multiplayer_cursor >= MULTIPLAYER_ITEMS) + m_multiplayer_cursor = 0; + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + if (--m_multiplayer_cursor < 0) + m_multiplayer_cursor = MULTIPLAYER_ITEMS - 1; + break; + + case K_MOUSE1: + case K_CTRL: + m_entersound = true; + switch (m_multiplayer_cursor) + { + case 0: + M_Menu_ServerList_f (); + break; + + case 1: + if (serialAvailable || ipxAvailable || tcpipAvailable) + M_Menu_Net_f (); + break; + + case 2: + if (serialAvailable || ipxAvailable || tcpipAvailable) + M_Menu_Net_f (); + break; + + case 3: + M_Menu_Setup_f (); + break; + } + } +} + +//============================================================================= +/* SETUP MENU */ + +int setup_cursor = 4; +int setup_cursor_table[] = {40, 56, 80, 104, 140}; + +char setup_hostname[16]; +char setup_myname[16]; +int setup_oldtop; +int setup_oldbottom; +int setup_top; +int setup_bottom; + +#define NUM_SETUP_CMDS 5 + +qboolean from_namemaker = false; + +void M_Menu_Setup_f (void) { + key_dest = key_menu; + m_state = m_setup; + m_entersound = true; + + if (from_namemaker) + from_namemaker = !from_namemaker; + else + Q_strcpy(setup_myname, cl_name.string); + + Q_strcpy(setup_hostname, hostname.string); + setup_top = setup_oldtop = ((int)cl_color.value) >> 4; + setup_bottom = setup_oldbottom = ((int)cl_color.value) & 15; +} + +void M_Setup_Draw (void) { + qpic_t *p; + + // M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/p_multi.lmp"); + M_DrawPic ( (/*320*/min_vid_width-p->width)/2, 4, p); + + M_Print (66, 40, "Hostname"); + M_DrawTextBox (160, 32, 16, 1); + M_Print (168, 40, setup_hostname); + + M_Print (64, 56, "Your name"); + M_DrawTextBox (160, 48, 16, 1); + M_Print (168, 56, setup_myname); + + M_Print (64, 80, "Shirt color"); + M_Print (64, 104, "Pants color"); + + M_DrawTextBox (64, 140-8, 14, 1); + M_Print (72, 140, "Accept Changes"); + + p = Draw_CachePic ("gfx/bigbox.lmp"); + M_DrawTransPic (160, 64, p); + p = Draw_CachePic ("gfx/menuplyr.lmp"); + M_BuildTranslationTable(setup_top*16, setup_bottom*16); + M_DrawTransPicTranslate (172, 72, p); + + M_DrawCharacter (56, setup_cursor_table [setup_cursor], 12+((int)(realtime*4)&1)); + + if (setup_cursor == 0) + M_DrawCharacter (168 + 8*strlen(setup_hostname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1)); + + if (setup_cursor == 1) + M_DrawCharacter (168 + 8*strlen(setup_myname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1)); +} + +void M_Setup_Key (int k) +{ + int l; + + switch (k) + { + case K_ESCAPE: + case K_ALT: + M_Menu_MultiPlayer_f (); + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + setup_cursor--; + if (setup_cursor < 0) + setup_cursor = NUM_SETUP_CMDS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + setup_cursor++; + if (setup_cursor >= NUM_SETUP_CMDS) + setup_cursor = 0; + break; + + case K_LEFTARROW: + if (setup_cursor < 2) + return; + S_LocalSound ("misc/menu3.wav"); + if (setup_cursor == 2) + setup_top = setup_top - 1; + if (setup_cursor == 3) + setup_bottom = setup_bottom - 1; + break; + case K_RIGHTARROW: + if (setup_cursor < 2) + return; +forward: + S_LocalSound ("misc/menu3.wav"); + if (setup_cursor == 2) + setup_top = setup_top + 1; + if (setup_cursor == 3) + setup_bottom = setup_bottom + 1; + break; + + case K_MOUSE1: + case K_CTRL: + if (setup_cursor == 0) + return; + + if (setup_cursor == 1) { + m_entersound = true; + command_kayboard = 0; + M_Menu_NameMaker_f (); + break; + } + + if (setup_cursor == 2 || setup_cursor == 3) + goto forward; + + // setup_cursor == 4 (OK) + if (Q_strcmp(cl_name.string, setup_myname) != 0) + Cbuf_AddText ( va ("name \"%s\"\n", setup_myname) ); + if (Q_strcmp(hostname.string, setup_hostname) != 0) + Cvar_Set("hostname", setup_hostname); + if (setup_top != setup_oldtop || setup_bottom != setup_oldbottom) + Cbuf_AddText( va ("color %i %i\n", setup_top, setup_bottom) ); + m_entersound = true; + M_Menu_MultiPlayer_f (); + break; + + case K_BACKSPACE: + if (setup_cursor == 0) + { + if (strlen(setup_hostname)) + setup_hostname[strlen(setup_hostname)-1] = 0; + } + + if (setup_cursor == 1) { + if (strlen(setup_myname)) + setup_myname[strlen(setup_myname)-1] = 0; + } + break; + + default: + if (k < 32 || k > 127) + break; + if (setup_cursor == 0) { + l = strlen(setup_hostname); + if (l < 15) { + setup_hostname[l+1] = 0; + setup_hostname[l] = k; + } + } + if (setup_cursor == 1) { + l = strlen(setup_myname); + if (l < 15) { + setup_myname[l+1] = 0; + setup_myname[l] = k; + } + } + } + + if (setup_top > 13) + setup_top = 0; + if (setup_top < 0) + setup_top = 13; + if (setup_bottom > 13) + setup_bottom = 0; + if (setup_bottom < 0) + setup_bottom = 13; +} + +//============================================================================= +/* NAME MAKER MENU */ + +int namemaker_cursor_x, namemaker_cursor_y; +#define NAMEMAKER_TABLE_SIZE 16 + +char command_name[16]; +char namemaker_name[16]; + +void M_Menu_NameMaker_f (void) { + key_dest = key_menu; + m_state = m_namemaker; + m_entersound = true; + Q_strncpyz (command_name, command.string, sizeof(command_name)); + Q_strncpyz (namemaker_name, cl_name.string, sizeof(namemaker_name)); +} + +void M_NameMaker_Draw (void) { + int x, y; + + M_DrawTextBox (92, 32, 15, 1); + + if (command_kayboard == 1) { + M_Print (20, 40, "Command"); + M_PrintWhite (104, 40, command_name); + } else { + M_Print (20, 40, "Your name"); + M_PrintWhite (104, 40, namemaker_name); + } + + M_DrawTextBox (16, 48, 33, 18); + + M_DrawTextBox (240, 32, 6, 1); + M_Print (252, 40, "Enter"); + + for (y = 0; y < NAMEMAKER_TABLE_SIZE ;y++) + for (x=0 ; x NAMEMAKER_TABLE_SIZE) + namemaker_cursor_y = 0; + break; + + case K_PGUP: + S_LocalSound ("misc/menu1.wav"); + namemaker_cursor_y = 0; + break; + + case K_PGDN: + S_LocalSound ("misc/menu1.wav"); + namemaker_cursor_y = NAMEMAKER_TABLE_SIZE; + break; + + case K_LEFTARROW: + S_LocalSound ("misc/menu1.wav"); + namemaker_cursor_x--; + if (namemaker_cursor_x < 0) + namemaker_cursor_x = NAMEMAKER_TABLE_SIZE - 1; + break; + + case K_RIGHTARROW: + S_LocalSound ("misc/menu1.wav"); + namemaker_cursor_x++; + if (namemaker_cursor_x >= NAMEMAKER_TABLE_SIZE) + namemaker_cursor_x = 0; + break; + + case K_HOME: + S_LocalSound ("misc/menu1.wav"); + namemaker_cursor_x = 0; + break; + + case K_END: + S_LocalSound ("misc/menu1.wav"); + namemaker_cursor_x = NAMEMAKER_TABLE_SIZE - 1; + break; + + case K_SPACE: + if (command_kayboard == 1) { + if ((l = strlen(command_name))) + command_name[l-1] = 0; + } else { + if ((l = strlen(namemaker_name))) + namemaker_name[l-1] = 0; + } + break; + + case K_CTRL: + if (namemaker_cursor_y == NAMEMAKER_TABLE_SIZE) { + if (command_kayboard == 1) { + sprintf (command, "%s\n", command_name); + Cbuf_InsertText (command); + Con_ToggleConsole_f (); + } else { + Q_strncpyz (setup_myname, namemaker_name, sizeof(setup_myname)); + from_namemaker = true; + M_Menu_Setup_f (); + } + } else { + if (command_kayboard == 1) { + l = strlen(command_name); + if (l < 15) { + command_name[l] = NAMEMAKER_TABLE_SIZE * namemaker_cursor_y + namemaker_cursor_x; + command_name[l+1] = 0; + } + } else { + l = strlen(namemaker_name); + if (l < 15) { + namemaker_name[l] = NAMEMAKER_TABLE_SIZE * namemaker_cursor_y + namemaker_cursor_x; + namemaker_name[l+1] = 0; + } + } + } + break; + + default: + if (key < 32 || key > 127) + break; + + Key_Extra (&key); + + if (command_kayboard == 1) { + l = strlen(command_name); + if (l < 15) { + command_name[l] = key; + command_name[l+1] = 0; + } + } else { + l = strlen(namemaker_name); + if (l < 15) { + namemaker_name[l] = key; + namemaker_name[l+1] = 0; + } + } + break; + } +} + +//============================================================================= +/* NET MENU */ + +int m_net_cursor; +int m_net_items; +int m_net_saveHeight; + +char *net_helpMessage [] = +{ +/* .........1.........2.... */ + " ", + " Two computers connected", + " through two modems. ", + " ", + + " ", + " Two computers connected", + " by a null-modem cable. ", + " ", + + " Novell network LANs ", + " or Windows 95 DOS-box. ", + " ", + "(LAN=Local Area Network)", + + " Commonly used to play ", + " over the Internet, but ", + " also used on a Local ", + " Area Network. " +}; + +void M_Menu_Net_f (void) +{ + key_dest = key_menu; + m_state = m_net; + m_entersound = true; + m_net_items = 4; + + if (m_net_cursor >= m_net_items) + m_net_cursor = 0; + m_net_cursor--; + M_Net_Key (K_DOWNARROW); +} + + +void M_Net_Draw (void) +{ + int f; + qpic_t *p; + + M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/p_multi.lmp"); + M_DrawPic ( (/*320*/min_vid_width-p->width)/2, 4, p); + + f = 32; + + if (serialAvailable) + { + p = Draw_CachePic ("gfx/netmen1.lmp"); + } + else + { +#ifdef _WIN32 + p = NULL; +#else + p = Draw_CachePic ("gfx/dim_modm.lmp"); +#endif + } + + if (p) + M_DrawTransPic (72, f, p); + + f += 19; + + if (serialAvailable) + { + p = Draw_CachePic ("gfx/netmen2.lmp"); + } + else + { +#ifdef _WIN32 + p = NULL; +#else + p = Draw_CachePic ("gfx/dim_drct.lmp"); +#endif + } + + if (p) + M_DrawTransPic (72, f, p); + + f += 19; + if (ipxAvailable) + p = Draw_CachePic ("gfx/netmen3.lmp"); + else + p = Draw_CachePic ("gfx/dim_ipx.lmp"); + M_DrawTransPic (72, f, p); + + f += 19; + if (tcpipAvailable) + p = Draw_CachePic ("gfx/netmen4.lmp"); + else + p = Draw_CachePic ("gfx/dim_tcp.lmp"); + M_DrawTransPic (72, f, p); + + if (m_net_items == 5) // JDC, could just be removed + { + f += 19; + p = Draw_CachePic ("gfx/netmen5.lmp"); + M_DrawTransPic (72, f, p); + } + + f = (/*320*/min_vid_width-26*8)/2; + M_DrawTextBox (f, 134, 24, 4); + f += 8; + M_Print (f, 142, net_helpMessage[m_net_cursor*4+0]); + M_Print (f, 150, net_helpMessage[m_net_cursor*4+1]); + M_Print (f, 158, net_helpMessage[m_net_cursor*4+2]); + M_Print (f, 166, net_helpMessage[m_net_cursor*4+3]); + + f = (int)(host_time * 10)%6; + M_DrawTransPic (54, 32 + m_net_cursor * 20,Draw_CachePic( va("gfx/menudot%i.lmp", f+1 ) ) ); +} + + +void M_Net_Key (int k) +{ +again: + switch (k) + { + case K_ESCAPE: + case K_ALT: + M_Menu_MultiPlayer_f (); + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + if (++m_net_cursor >= m_net_items) + m_net_cursor = 0; + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + if (--m_net_cursor < 0) + m_net_cursor = m_net_items - 1; + break; + + case K_MOUSE1: + case K_CTRL: + m_entersound = true; + + switch (m_net_cursor) + { + case 0: + M_Menu_SerialConfig_f (); + break; + + case 1: + M_Menu_SerialConfig_f (); + break; + + case 2: + M_Menu_LanConfig_f (); + break; + + case 3: + M_Menu_LanConfig_f (); + break; + + case 4: +// multiprotocol + break; + } + } + + if (m_net_cursor == 0 && !serialAvailable) + goto again; + if (m_net_cursor == 1 && !serialAvailable) + goto again; + if (m_net_cursor == 2 && !ipxAvailable) + goto again; + if (m_net_cursor == 3 && !tcpipAvailable) + goto again; +} + +//============================================================================= +/* OPTIONS MENU */ + +#ifdef _WIN32 +#define OPTIONS_ITEMS 14 +#else +#define OPTIONS_ITEMS 12 +#endif + +#define SLIDER_RANGE 10 + +int options_cursor; + +void M_Menu_Options_f (void) { + key_dest = key_menu; + m_state = m_options; + m_entersound = true; + +#ifdef _WIN32 + if ((options_cursor == 13) && (modestate != MS_WINDOWED)) { + options_cursor = 0; + } +#endif +} + + +void M_AdjustSliders (int dir) { + S_LocalSound ("misc/menu3.wav"); + + switch (options_cursor) { + case 0: // Load Configs + Cvar_SetValue ("cl_config", cl_config.value + dir*1); + + if (cl_config.value > 2) + Cvar_SetValue ("cl_config", 0); + if (cl_config.value == 0) + Cbuf_InsertText ("exec config1.cfg\n"); + if (cl_config.value == 1) + Cbuf_InsertText ("exec config2.cfg\n"); + if (cl_config.value == 2) + Cbuf_InsertText ("exec userconfig.cfg\n"); + if (cl_config.value < 0) + Cvar_SetValue ("cl_config", 2); + break; + case 4: // screen size + scr_viewsize.value += dir * 10; + if (scr_viewsize.value < 30) + scr_viewsize.value = 30; + if (scr_viewsize.value > 120) + scr_viewsize.value = 120; + Cvar_SetValue ("viewsize", scr_viewsize.value); + break; + case 5: // gamma + v_gamma.value -= (float)(dir * 0.05); + if (v_gamma.value < 0.5) + v_gamma.value = 0.5; + if (v_gamma.value > 1) + v_gamma.value = 1; + Cvar_SetValue ("gamma", v_gamma.value); + break; + /* + case 5: // mouse speed + sensitivity.value += (float)(dir * 0.5); + if (sensitivity.value < 1) + sensitivity.value = 1; + if (sensitivity.value > 11) + sensitivity.value = 11; + Cvar_SetValue ("sensitivity", sensitivity.value); + break; + */ + case 6: // music volume +#ifdef _WIN32 + bgmvolume.value += (float)(dir * 1.0); +#else + bgmvolume.value += (float)(dir * 0.1); +#endif + if (bgmvolume.value < 0) { + bgmvolume.value = 0; + CDAudio_Pause(); + } + if ((bgmvolume.value>0) && (bgmvolume.value<0.2) && (dir==1)) { + CDAudio_Resume(); + } + if (bgmvolume.value > 1) + bgmvolume.value = 1; + Cvar_SetValue ("bgmvolume", bgmvolume.value); + break; + case 7: // sfx volume + volume.value += (float)(dir * 0.1); + if (volume.value < 0) + volume.value = 0; + if (volume.value > 1) + volume.value = 1; + Cvar_SetValue ("volume", volume.value); + break; + + case 8: // allways run + if (cl_forwardspeed.value > 200) + { + Cvar_SetValue ("cl_forwardspeed", 200); + Cvar_SetValue ("cl_backspeed", 200); + } + else + { + Cvar_SetValue ("cl_forwardspeed", 400); + Cvar_SetValue ("cl_backspeed", 400); + } + break; + /* + case 9: // invert mouse + Cvar_SetValue ("m_pitch", -m_pitch.value); + break; + */ + case 9: // lookspring + Cvar_SetValue ("lookspring", (float)!lookspring.value); + break; + + case 10: // lookstrafe + Cvar_SetValue ("lookstrafe", (float)!lookstrafe.value); + break; + case 11: // Show FPS + Cvar_SetValue ("cl_showfps", (float)!cl_showfps.value); + break; + /* + case 10: // doublesizeset + Cvar_SetValue ("doublesizeset", (int)!doublesizeset.value); + if (doublesizeset.value) { + scr_viewsize.value = 50; + } else { + scr_viewsize.value = 100; + } + Cvar_SetValue ("viewsize", scr_viewsize.value); + vid.recalc_refdef = 1; + break; + + case 11: // doublesize status bar + Cvar_SetValue ("doublesizestatus", (int)!doublesizestatus.value); vid.recalc_refdef = 1; + break; + */ +#ifdef _WIN32 + case 13: // _windowed_mouse + Cvar_SetValue ("_windowed_mouse", (float)!_windowed_mouse.value); + break; +#endif + } +} + + +void M_DrawSlider (int x, int y, float range) { + int i; + + if (range < 0) + range = 0; + if (range > 1) + range = 1; + M_DrawCharacter (x-8, y, 128); + for (i=0 ; iwidth)/2, 4, p); + + M_Print (16, 32, " Setting"); + if (cl_config.value == 0) + M_Print (140, 32, "Config 1"); + if (cl_config.value == 1) + M_Print (140, 32, "Config 2"); + if (cl_config.value == 2) + M_Print (140, 32, "Custom Config"); + + M_Print (16, 40, " Controls"); + //M_Print (16, 32, " Customize controls"); + M_Print (16, 48, " Command"); + M_Print (16, 56, " Defaults"); + + M_Print (16, 64, " Screen size"); + r = (scr_viewsize.value - 30) / (120 - 30); + M_DrawSlider (148/*220*/, 64, r); + + M_Print (16, 72, " Brightness"); + r = (float)((1.0 - v_gamma.value) / 0.5); + M_DrawSlider (148/*220*/, 72, r); + + /* M_Print (16, 72, " Mouse Speed"); + r = (sensitivity.value - 1)/10; + M_DrawSlider (148, 72, r); */ + + M_Print (16, 80, " CD Volume"); + r = bgmvolume.value; + M_DrawSlider (148/*220*/, 80, r); + + M_Print (16, 88, " Sound Volume"); + r = volume.value; + M_DrawSlider (148/*220*/, 88, r); + + M_Print (16, 96, " Always Run"); + M_DrawCheckbox (140/*220*/, 96, cl_forwardspeed.value > 200); + + /* M_Print (16, 104, " Invert Mouse"); + M_DrawCheckbox (140, 104, m_pitch.value < 0); */ + + M_Print (16, 104, " Lookspring"); + M_DrawCheckbox (140/*220*/, 104, (int)lookspring.value); + + M_Print (16, 112, " Lookstrafe"); + M_DrawCheckbox (140/*220*/, 112, (int)lookstrafe.value); + + M_Print (16, 120, " Show FPS"); + M_DrawCheckbox (140/*220*/, 120, (int)cl_showfps.value); + + /* M_Print (16, 112, " Double Size"); + M_DrawCheckbox (140, 112, (int)doublesizeset.value); + + M_Print (16, 120, " DS SBar"); + M_DrawCheckbox (140, 120, (int)doublesizestatus.value); */ + + if (vid_menudrawfn) + M_Print (16, 128, " Video"); + +#ifdef _WIN32 + if (modestate == MS_WINDOWED) + { + M_Print (16, 136, " Use Mouse"); + M_DrawCheckbox (148/*220*/, 136, (int)_windowed_mouse.value); + } +#endif + +// cursor + M_DrawCharacter (132/*220*/, 32 + options_cursor*8, 12+((int)(realtime*4)&1)); + +// Config Info + if (options_cursor == 3) { + if (cl_config.value == 2) + M_Print (48, 212, "Press A-Button to set Default"); + else + M_Print (40, 212, "Can use only with Custom Config"); + } +} + + +void M_Options_Key (int k) { + switch (k) { + case K_ESCAPE: + case K_ALT: + M_Menu_Main_f (); + break; + + case K_CTRL: + case K_MOUSE1: + m_entersound = true; + switch (options_cursor) { + case 1: + if (cl_config.value == 2) + M_Menu_Keys_f (); + break; + case 2: + m_state = m_none; + command_kayboard = 1; + M_Menu_NameMaker_f (); + // Con_ToggleConsole_f (); + break; + case 3: + if (cl_config.value == 2) + Cbuf_AddText ("exec default.cfg\n"); + break; + // case 12: + // M_Menu_Video_f (); + // break; + default: + M_AdjustSliders (1); + break; + } + return; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + options_cursor--; + if (options_cursor < 0) + options_cursor = OPTIONS_ITEMS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + options_cursor++; + if (options_cursor >= OPTIONS_ITEMS) + options_cursor = 0; + break; + + case K_LEFTARROW: + M_AdjustSliders (-1); + break; + + case K_RIGHTARROW: + M_AdjustSliders (1); + break; + } + + if (options_cursor == 13 && vid_menudrawfn == NULL) { + if (k == K_UPARROW) + options_cursor = 12; + else + options_cursor = 0; + } + +#ifdef _WIN32 + if ((options_cursor == 13) && (modestate != MS_WINDOWED)) { + if (k == K_UPARROW) + options_cursor = 12; + else + options_cursor = 0; + } +#endif +} + +//============================================================================= +/* KEYS MENU */ + +char *bindnames[][2] = +{ +{"+attack", "attack"}, +{"impulse 10", "change weapon"}, +{"+jump", "jump / swim up"}, +{"+forward", "walk forward"}, +{"+back", "backpedal"}, +{"+left", "turn left"}, +{"+right", "turn right"}, +{"+speed", "run"}, +{"+moveleft", "step left"}, +{"+moveright", "step right"}, +{"+strafe", "sidestep"}, +{"+lookup", "look up"}, +{"+lookdown", "look down"}, +{"centerview", "center view"}, +{"+mlook", "mouse look"}, +{"+klook", "keyboard look"}, +{"+moveup", "swim up"}, +{"+movedown", "swim down"} +}; + +#define NUMCOMMANDS (sizeof(bindnames)/sizeof(bindnames[0])) + +int keys_cursor; +int bind_grab; + +void M_Menu_Keys_f (void) +{ + key_dest = key_menu; + m_state = m_keys; + m_entersound = true; +} + + +void M_FindKeysForCommand (char *command, int *twokeys) +{ + int count; + int j; + int l; + char *b; + + twokeys[0] = twokeys[1] = -1; + l = strlen(command); + count = 0; + + for (j=0 ; j<256 ; j++) + { + b = keybindings[j]; + if (!b) + continue; + if (!strncmp (b, command, l) ) + { + twokeys[count] = j; + count++; + if (count == 2) + break; + } + } +} + +void M_UnbindCommand (char *command) +{ + int j; + int l; + char *b; + + l = strlen(command); + + for (j=0 ; j<256 ; j++) + { + b = keybindings[j]; + if (!b) + continue; + if (!strncmp (b, command, l) ) + Key_SetBinding (j, ""); + } +} + + +void M_Keys_Draw (void) +{ + int i, l; + int keys[2]; + char *name; + int x, y; + qpic_t *p; + + p = Draw_CachePic ("gfx/ttl_cstm.lmp"); + M_DrawPic ( (/*320*/min_vid_width-p->width)/2, 4, p); + + if (bind_grab) + M_Print (12, 32, "Press a key or button for this action"); + else + M_Print (18, 32, "Enter to change, backspace to clear"); + +// search for known bindings + for (i=0 ; i= NUMCOMMANDS) + keys_cursor = 0; + break; + + case K_CTRL: + case K_MOUSE1: // go into bind mode + M_FindKeysForCommand (bindnames[keys_cursor][0], keys); + S_LocalSound ("misc/menu2.wav"); + if (keys[1] != -1) + M_UnbindCommand (bindnames[keys_cursor][0]); + bind_grab = true; + break; + + case K_BACKSPACE: // delete bindings + case K_DEL: // delete bindings + S_LocalSound ("misc/menu2.wav"); + M_UnbindCommand (bindnames[keys_cursor][0]); + break; + } +} + +//============================================================================= +/* VIDEO MENU */ + +void M_Menu_Video_f (void) +{ + key_dest = key_menu; + m_state = m_video; + m_entersound = true; +} + + +void M_Video_Draw (void) +{ + (*vid_menudrawfn) (); +} + + +void M_Video_Key (int key) +{ + (*vid_menukeyfn) (key); +} + +//============================================================================= +/* HELP MENU */ + +int help_page; +#define NUM_HELP_PAGES 6 + + +void M_Menu_Help_f (void) +{ + key_dest = key_menu; + m_state = m_help; + m_entersound = true; + help_page = 0; +} + + + +void M_Help_Draw (void) +{ + M_DrawPic (0, 0, Draw_CachePic ( va("gfx/help%i.lmp", help_page)) ); +} + + +void M_Help_Key (int key) +{ + switch (key) + { + case K_ESCAPE: + case K_ALT: + M_Menu_Main_f (); + break; + + case K_UPARROW: + case K_RIGHTARROW: + m_entersound = true; + if (++help_page >= NUM_HELP_PAGES) + help_page = 0; + break; + + case K_DOWNARROW: + case K_LEFTARROW: + m_entersound = true; + if (--help_page < 0) + help_page = NUM_HELP_PAGES-1; + break; + } + +} + +//============================================================================= +/* QUIT MENU */ + +int msgNumber; +int m_quit_prevstate; +qboolean wasInMenus; + +#ifndef _WIN32 +char *quitMessage [] = +{ +/* .........1.........2.... */ + " Are you gonna quit ", + " this game just like ", + " everything else? ", + " ", + + " Milord, methinks that ", + " thou art a lowly ", + " quitter. Is this true? ", + " ", + + " Do I need to bust your ", + " face open for trying ", + " to quit? ", + " ", + + " Man, I oughta smack you", + " for trying to quit! ", + " Press Y to get ", + " smacked out. ", + + " Press Y to quit like a ", + " big loser in life. ", + " Press N to stay proud ", + " and successful! ", + + " Um, Asmodeus dislikes ", + " his children trying to ", + " quit. Press Y to return", + " to your Tinkertoys. ", + + " If you quit now, I'll ", + " throw a blanket-party ", + " for you next time! ", + " " +}; +#endif + +void M_Menu_Quit_f (void) +{ + if (m_state == m_quit) + return; + + wasInMenus = (key_dest == key_menu); + key_dest = key_menu; + m_quit_prevstate = m_state; + m_state = m_quit; + m_entersound = true; + msgNumber = rand()&6; +} + + +void M_Quit_Key (int key) +{ + switch (key) + { + case K_ESCAPE: + case K_ALT: + case 'n': + case 'N': + if (wasInMenus) + { + m_state = m_quit_prevstate; + m_entersound = true; + } + else + { + key_dest = key_game; + m_state = m_none; + } + break; + + case 'Y': + case 'y': + case K_CTRL: + case K_MOUSE1: + key_dest = key_console; + Host_Quit_f (); + break; + + default: + break; + } + +} + + +void M_Quit_Draw (void) { + if (wasInMenus) { + m_state = m_quit_prevstate; + m_recursiveDraw = true; + M_Draw (); + m_state = m_quit; + } + + M_DrawTextBox (56, 76, 24, 4); + M_Print (64, 84, quitMessage[msgNumber*4+0]); + M_Print (64, 92, quitMessage[msgNumber*4+1]); + M_Print (64, 100, quitMessage[msgNumber*4+2]); + M_Print (64, 108, quitMessage[msgNumber*4+3]); +} + +//============================================================================= + +/* SERIAL CONFIG MENU */ + +int serialConfig_cursor; +int serialConfig_cursor_table[] = {48, 64, 80, 96, 112, 132}; +#define NUM_SERIALCONFIG_CMDS 6 + +static int ISA_uarts[] = {0x3f8,0x2f8,0x3e8,0x2e8}; +static int ISA_IRQs[] = {4,3,4,3}; +int serialConfig_baudrate[] = {9600,14400,19200,28800,38400,57600}; + +int serialConfig_comport; +int serialConfig_irq ; +int serialConfig_baud; +char serialConfig_phone[16]; + +void M_Menu_SerialConfig_f (void) +{ + int n; + int port; + int baudrate; + qboolean useModem; + + key_dest = key_menu; + m_state = m_serialconfig; + m_entersound = true; + if (JoiningGame && SerialConfig) + serialConfig_cursor = 4; + else + serialConfig_cursor = 5; + + (*GetComPortConfig) (0, &port, &serialConfig_irq, &baudrate, &useModem); + + // map uart's port to COMx + for (n = 0; n < 4; n++) + if (ISA_uarts[n] == port) + break; + if (n == 4) + { + n = 0; + serialConfig_irq = 4; + } + serialConfig_comport = n + 1; + + // map baudrate to index + for (n = 0; n < 6; n++) + if (serialConfig_baudrate[n] == baudrate) + break; + if (n == 6) + n = 5; + serialConfig_baud = n; + + m_return_onerror = false; + m_return_reason[0] = 0; +} + + +void M_SerialConfig_Draw (void) +{ + qpic_t *p; + int basex; + char *startJoin; + char *directModem; + + // M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/p_multi.lmp"); + basex = (/*320*/min_vid_width-p->width)/2; + M_DrawPic (basex, 4, p); + + if (StartingGame) + startJoin = "New Game"; + else + startJoin = "Join Game"; + if (SerialConfig) + directModem = "Modem"; + else + directModem = "Direct Connect"; + M_Print (basex, 32, va ("%s - %s", startJoin, directModem)); + basex += 8; + + M_Print (basex, serialConfig_cursor_table[0], "Port"); + M_DrawTextBox (160, 40, 4, 1); + M_Print (168, serialConfig_cursor_table[0], va("COM%u", serialConfig_comport)); + + M_Print (basex, serialConfig_cursor_table[1], "IRQ"); + M_DrawTextBox (160, serialConfig_cursor_table[1]-8, 1, 1); + M_Print (168, serialConfig_cursor_table[1], va("%u", serialConfig_irq)); + + M_Print (basex, serialConfig_cursor_table[2], "Baud"); + M_DrawTextBox (160, serialConfig_cursor_table[2]-8, 5, 1); + M_Print (168, serialConfig_cursor_table[2], va("%u", serialConfig_baudrate[serialConfig_baud])); + + if (SerialConfig) { + M_Print (basex, serialConfig_cursor_table[3], "Modem Setup..."); + if (JoiningGame) { + M_Print (basex, serialConfig_cursor_table[4], "Phone number"); + M_DrawTextBox (160, serialConfig_cursor_table[4]-8, 16, 1); + M_Print (168, serialConfig_cursor_table[4], serialConfig_phone); + } + } + + if (JoiningGame) { + M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 7, 1); + M_Print (basex+8, serialConfig_cursor_table[5], "Connect"); + } else { + M_DrawTextBox (basex, serialConfig_cursor_table[5]-8, 2, 1); + M_Print (basex+8, serialConfig_cursor_table[5], "OK"); + } + + M_DrawCharacter (basex-8, serialConfig_cursor_table [serialConfig_cursor], 12+((int)(realtime*4)&1)); + + if (serialConfig_cursor == 4) + M_DrawCharacter (168 + 8*strlen(serialConfig_phone), serialConfig_cursor_table [serialConfig_cursor], 10+((int)(realtime*4)&1)); + + if (*m_return_reason) + M_PrintWhite (basex, 148, m_return_reason); +} + + +void M_SerialConfig_Key (int key) +{ + int l; + + switch (key) + { + case K_ESCAPE: + case K_ALT: + M_Menu_Net_f (); + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + serialConfig_cursor--; + if (serialConfig_cursor < 0) + serialConfig_cursor = NUM_SERIALCONFIG_CMDS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + serialConfig_cursor++; + if (serialConfig_cursor >= NUM_SERIALCONFIG_CMDS) + serialConfig_cursor = 0; + break; + + case K_LEFTARROW: + if (serialConfig_cursor > 2) + break; + S_LocalSound ("misc/menu3.wav"); + + if (serialConfig_cursor == 0) { + serialConfig_comport--; + if (serialConfig_comport == 0) + serialConfig_comport = 4; + serialConfig_irq = ISA_IRQs[serialConfig_comport-1]; + } + + if (serialConfig_cursor == 1) { + serialConfig_irq--; + if (serialConfig_irq == 6) + serialConfig_irq = 5; + if (serialConfig_irq == 1) + serialConfig_irq = 7; + } + + if (serialConfig_cursor == 2) { + serialConfig_baud--; + if (serialConfig_baud < 0) + serialConfig_baud = 5; + } + + break; + + case K_RIGHTARROW: + if (serialConfig_cursor > 2) + break; +forward: + S_LocalSound ("misc/menu3.wav"); + + if (serialConfig_cursor == 0) + { + serialConfig_comport++; + if (serialConfig_comport > 4) + serialConfig_comport = 1; + serialConfig_irq = ISA_IRQs[serialConfig_comport-1]; + } + + if (serialConfig_cursor == 1) + { + serialConfig_irq++; + if (serialConfig_irq == 6) + serialConfig_irq = 7; + if (serialConfig_irq == 8) + serialConfig_irq = 2; + } + + if (serialConfig_cursor == 2) + { + serialConfig_baud++; + if (serialConfig_baud > 5) + serialConfig_baud = 0; + } + + break; + + case K_CTRL: + case K_MOUSE1: + if (serialConfig_cursor < 3) + goto forward; + + m_entersound = true; + + if (serialConfig_cursor == 3) { + (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig); + + M_Menu_ModemConfig_f (); + break; + } + + if (serialConfig_cursor == 4) { + serialConfig_cursor = 5; + break; + } + + // serialConfig_cursor == 5 (OK/CONNECT) + (*SetComPortConfig) (0, ISA_uarts[serialConfig_comport-1], serialConfig_irq, serialConfig_baudrate[serialConfig_baud], SerialConfig); + + M_ConfigureNetSubsystem (); + + if (StartingGame) { + M_Menu_GameOptions_f (); + break; + } + + m_return_state = m_state; + m_return_onerror = true; + key_dest = key_game; + m_state = m_none; + + if (SerialConfig) + Cbuf_AddText (va ("connect \"%s\"\n", serialConfig_phone)); + else + Cbuf_AddText ("connect\n"); + break; + + case K_BACKSPACE: + if (serialConfig_cursor == 4) + { + if (strlen(serialConfig_phone)) + serialConfig_phone[strlen(serialConfig_phone)-1] = 0; + } + break; + + default: + if (key < 32 || key > 127) + break; + if (serialConfig_cursor == 4) + { + l = strlen(serialConfig_phone); + if (l < 15) + { + serialConfig_phone[l+1] = 0; + serialConfig_phone[l] = key; + } + } + } + + if (DirectConfig && (serialConfig_cursor == 3 || serialConfig_cursor == 4)) + if (key == K_UPARROW) + serialConfig_cursor = 2; + else + serialConfig_cursor = 5; + + if (SerialConfig && StartingGame && serialConfig_cursor == 4) + if (key == K_UPARROW) + serialConfig_cursor = 3; + else + serialConfig_cursor = 5; +} + +//============================================================================= +/* MODEM CONFIG MENU */ + +int modemConfig_cursor; +int modemConfig_cursor_table [] = {40, 56, 88, 120, 156}; +#define NUM_MODEMCONFIG_CMDS 5 + +char modemConfig_dialing; +char modemConfig_clear [16]; +char modemConfig_init [32]; +char modemConfig_hangup [16]; + +void M_Menu_ModemConfig_f (void) +{ + key_dest = key_menu; + m_state = m_modemconfig; + m_entersound = true; + (*GetModemConfig) (0, &modemConfig_dialing, modemConfig_clear, modemConfig_init, modemConfig_hangup); +} + + +void M_ModemConfig_Draw (void) +{ + qpic_t *p; + int basex; + + // M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/p_multi.lmp"); + basex = (/*320*/min_vid_width-p->width)/2; + M_DrawPic (basex, 4, p); + basex += 8; + + if (modemConfig_dialing == 'P') + M_Print (basex, modemConfig_cursor_table[0], "Pulse Dialing"); + else + M_Print (basex, modemConfig_cursor_table[0], "Touch Tone Dialing"); + + M_Print (basex, modemConfig_cursor_table[1], "Clear"); + M_DrawTextBox (basex, modemConfig_cursor_table[1]+4, 16, 1); + M_Print (basex+8, modemConfig_cursor_table[1]+12, modemConfig_clear); + if (modemConfig_cursor == 1) + M_DrawCharacter (basex+8 + 8*strlen(modemConfig_clear), modemConfig_cursor_table[1]+12, 10+((int)(realtime*4)&1)); + + M_Print (basex, modemConfig_cursor_table[2], "Init"); + M_DrawTextBox (basex, modemConfig_cursor_table[2]+4, 30, 1); + M_Print (basex+8, modemConfig_cursor_table[2]+12, modemConfig_init); + if (modemConfig_cursor == 2) + M_DrawCharacter (basex+8 + 8*strlen(modemConfig_init), modemConfig_cursor_table[2]+12, 10+((int)(realtime*4)&1)); + + M_Print (basex, modemConfig_cursor_table[3], "Hangup"); + M_DrawTextBox (basex, modemConfig_cursor_table[3]+4, 16, 1); + M_Print (basex+8, modemConfig_cursor_table[3]+12, modemConfig_hangup); + if (modemConfig_cursor == 3) + M_DrawCharacter (basex+8 + 8*strlen(modemConfig_hangup), modemConfig_cursor_table[3]+12, 10+((int)(realtime*4)&1)); + + M_DrawTextBox (basex, modemConfig_cursor_table[4]-8, 2, 1); + M_Print (basex+8, modemConfig_cursor_table[4], "OK"); + + M_DrawCharacter (basex-8, modemConfig_cursor_table [modemConfig_cursor], 12+((int)(realtime*4)&1)); +} + + +void M_ModemConfig_Key (int key) +{ + int l; + + switch (key) + { + case K_ESCAPE: + case K_ALT: + M_Menu_SerialConfig_f (); + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + modemConfig_cursor--; + if (modemConfig_cursor < 0) + modemConfig_cursor = NUM_MODEMCONFIG_CMDS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + modemConfig_cursor++; + if (modemConfig_cursor >= NUM_MODEMCONFIG_CMDS) + modemConfig_cursor = 0; + break; + + case K_LEFTARROW: + case K_RIGHTARROW: + if (modemConfig_cursor == 0) + { + if (modemConfig_dialing == 'P') + modemConfig_dialing = 'T'; + else + modemConfig_dialing = 'P'; + S_LocalSound ("misc/menu1.wav"); + } + break; + + case K_CTRL: + case K_MOUSE1: + if (modemConfig_cursor == 0) + { + if (modemConfig_dialing == 'P') + modemConfig_dialing = 'T'; + else + modemConfig_dialing = 'P'; + m_entersound = true; + } + + if (modemConfig_cursor == 4) + { + (*SetModemConfig) (0, va ("%c", modemConfig_dialing), modemConfig_clear, modemConfig_init, modemConfig_hangup); + m_entersound = true; + M_Menu_SerialConfig_f (); + } + break; + + case K_BACKSPACE: + if (modemConfig_cursor == 1) + { + if (strlen(modemConfig_clear)) + modemConfig_clear[strlen(modemConfig_clear)-1] = 0; + } + + if (modemConfig_cursor == 2) + { + if (strlen(modemConfig_init)) + modemConfig_init[strlen(modemConfig_init)-1] = 0; + } + + if (modemConfig_cursor == 3) + { + if (strlen(modemConfig_hangup)) + modemConfig_hangup[strlen(modemConfig_hangup)-1] = 0; + } + break; + + default: + if (key < 32 || key > 127) + break; + + if (modemConfig_cursor == 1) + { + l = strlen(modemConfig_clear); + if (l < 15) + { + modemConfig_clear[l+1] = 0; + modemConfig_clear[l] = key; + } + } + + if (modemConfig_cursor == 2) + { + l = strlen(modemConfig_init); + if (l < 29) + { + modemConfig_init[l+1] = 0; + modemConfig_init[l] = key; + } + } + + if (modemConfig_cursor == 3) + { + l = strlen(modemConfig_hangup); + if (l < 15) + { + modemConfig_hangup[l+1] = 0; + modemConfig_hangup[l] = key; + } + } + } +} + +//============================================================================= +/* LAN CONFIG MENU */ + +int lanConfig_cursor = -1; +int lanConfig_cursor_table [] = {72, 92, 124}; +#define NUM_LANCONFIG_CMDS 3 + +int lanConfig_port; +char lanConfig_portname[6]; +char lanConfig_joinname[22]; + +void M_Menu_LanConfig_f (void) +{ + key_dest = key_menu; + m_state = m_lanconfig; + m_entersound = true; + if (lanConfig_cursor == -1) + { + if (JoiningGame && TCPIPConfig) + lanConfig_cursor = 2; + else + lanConfig_cursor = 1; + } + if (StartingGame && lanConfig_cursor == 2) + lanConfig_cursor = 1; + lanConfig_port = DEFAULTnet_hostport; + sprintf(lanConfig_portname, "%u", lanConfig_port); + + m_return_onerror = false; + m_return_reason[0] = 0; +} + + +void M_LanConfig_Draw (void) +{ + qpic_t *p; + int basex; + char *startJoin; + char *protocol; + + // M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/p_multi.lmp"); + basex = (/*320*/min_vid_width-p->width)/2; + M_DrawPic (basex, 4, p); + + if (StartingGame) + startJoin = "New Game"; + else + startJoin = "Join Game"; + if (IPXConfig) + protocol = "IPX"; + else + protocol = "TCP/IP"; + M_Print (basex, 32, va ("%s - %s", startJoin, protocol)); + basex += 8; + + M_Print (basex, 52, "Address:"); + if (IPXConfig) + M_Print (basex+9*8, 52, my_ipx_address); + else + M_Print (basex+9*8, 52, my_tcpip_address); + + M_Print (basex, lanConfig_cursor_table[0], "Port"); + M_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, 6, 1); + M_Print (basex+9*8, lanConfig_cursor_table[0], lanConfig_portname); + + if (JoiningGame) { + M_Print (basex, lanConfig_cursor_table[1], "Search for local games..."); + M_Print (basex, 108, "Join game at:"); + M_DrawTextBox (basex+8, lanConfig_cursor_table[2]-8, 22, 1); + M_Print (basex+16, lanConfig_cursor_table[2], lanConfig_joinname); + } else { + M_DrawTextBox (basex, lanConfig_cursor_table[1]-8, 2, 1); + M_Print (basex+8, lanConfig_cursor_table[1], "OK"); + } + + M_DrawCharacter (basex-8, lanConfig_cursor_table [lanConfig_cursor], 12+((int)(realtime*4)&1)); + + if (lanConfig_cursor == 0) + M_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1)); + + if (lanConfig_cursor == 2) + M_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [2], 10+((int)(realtime*4)&1)); + + if (*m_return_reason) + M_PrintWhite (basex, 148, m_return_reason); +} + + +void M_LanConfig_Key (int key) { + int l; + + switch (key) { + case K_ESCAPE: + case K_ALT: + M_Menu_Net_f (); + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + lanConfig_cursor--; + if (lanConfig_cursor < 0) + lanConfig_cursor = NUM_LANCONFIG_CMDS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + lanConfig_cursor++; + if (lanConfig_cursor >= NUM_LANCONFIG_CMDS) + lanConfig_cursor = 0; + break; + + case K_CTRL: + case K_MOUSE1: + if (lanConfig_cursor == 0) + break; + + m_entersound = true; + + M_ConfigureNetSubsystem (); + + if (lanConfig_cursor == 1) { + if (StartingGame) { + M_Menu_GameOptions_f (); + break; + } + + M_Menu_Search_f(); + break; + } + + if (lanConfig_cursor == 2) { + m_return_state = m_state; + m_return_onerror = true; + key_dest = key_game; + m_state = m_none; + Cbuf_AddText ( va ("connect \"%s\"\n", lanConfig_joinname) ); + break; + } + + break; + + case K_BACKSPACE: + if (lanConfig_cursor == 0) + { + if (strlen(lanConfig_portname)) + lanConfig_portname[strlen(lanConfig_portname)-1] = 0; + } + + if (lanConfig_cursor == 2) + { + if (strlen(lanConfig_joinname)) + lanConfig_joinname[strlen(lanConfig_joinname)-1] = 0; + } + break; + + default: + if (key < 32 || key > 127) + break; + + if (lanConfig_cursor == 2) + { + l = strlen(lanConfig_joinname); + if (l < 21) + { + lanConfig_joinname[l+1] = 0; + lanConfig_joinname[l] = key; + } + } + + if (key < '0' || key > '9') + break; + if (lanConfig_cursor == 0) + { + l = strlen(lanConfig_portname); + if (l < 5) + { + lanConfig_portname[l+1] = 0; + lanConfig_portname[l] = key; + } + } + } + + if (StartingGame && lanConfig_cursor == 2) + if (key == K_UPARROW) + lanConfig_cursor = 1; + else + lanConfig_cursor = 0; + + l = Q_atoi(lanConfig_portname); + if (l > 65535) + l = lanConfig_port; + else + lanConfig_port = l; + sprintf(lanConfig_portname, "%u", lanConfig_port); +} + +//============================================================================= +/* GAME OPTIONS MENU */ + +typedef struct +{ + char *name; + char *description; +} level_t; + +level_t levels[] = +{ + {"start", "Entrance"}, // 0 + + {"e1m1", "Slipgate Complex"}, // 1 + {"e1m2", "Castle of the Damned"}, + {"e1m3", "The Necropolis"}, + {"e1m4", "The Grisly Grotto"}, + {"e1m5", "Gloom Keep"}, + {"e1m6", "The Door To Chthon"}, + {"e1m7", "The House of Chthon"}, + {"e1m8", "Ziggurat Vertigo"}, + + {"e2m1", "The Installation"}, // 9 + {"e2m2", "Ogre Citadel"}, + {"e2m3", "Crypt of Decay"}, + {"e2m4", "The Ebon Fortress"}, + {"e2m5", "The Wizard's Manse"}, + {"e2m6", "The Dismal Oubliette"}, + {"e2m7", "Underearth"}, + + {"e3m1", "Termination Central"}, // 16 + {"e3m2", "The Vaults of Zin"}, + {"e3m3", "The Tomb of Terror"}, + {"e3m4", "Satan's Dark Delight"}, + {"e3m5", "Wind Tunnels"}, + {"e3m6", "Chambers of Torment"}, + {"e3m7", "The Haunted Halls"}, + + {"e4m1", "The Sewage System"}, // 23 + {"e4m2", "The Tower of Despair"}, + {"e4m3", "The Elder God Shrine"}, + {"e4m4", "The Palace of Hate"}, + {"e4m5", "Hell's Atrium"}, + {"e4m6", "The Pain Maze"}, + {"e4m7", "Azure Agony"}, + {"e4m8", "The Nameless City"}, + + {"end", "Shub-Niggurath's Pit"}, // 31 + + {"dm1", "Place of Two Deaths"}, // 32 + {"dm2", "Claustrophobopolis"}, + {"dm3", "The Abandoned Base"}, + {"dm4", "The Bad Place"}, + {"dm5", "The Cistern"}, + {"dm6", "The Dark Zone"} +}; + +//MED 01/06/97 added hipnotic levels +level_t hipnoticlevels[] = +{ + {"start", "Command HQ"}, // 0 + + {"hip1m1", "The Pumping Station"}, // 1 + {"hip1m2", "Storage Facility"}, + {"hip1m3", "The Lost Mine"}, + {"hip1m4", "Research Facility"}, + {"hip1m5", "Military Complex"}, + + {"hip2m1", "Ancient Realms"}, // 6 + {"hip2m2", "The Black Cathedral"}, + {"hip2m3", "The Catacombs"}, + {"hip2m4", "The Crypt"}, + {"hip2m5", "Mortum's Keep"}, + {"hip2m6", "The Gremlin's Domain"}, + + {"hip3m1", "Tur Torment"}, // 12 + {"hip3m2", "Pandemonium"}, + {"hip3m3", "Limbo"}, + {"hip3m4", "The Gauntlet"}, + + {"hipend", "Armagon's Lair"}, // 16 + + {"hipdm1", "The Edge of Oblivion"} // 17 +}; + +//PGM 01/07/97 added rogue levels +//PGM 03/02/97 added dmatch level +level_t roguelevels[] = +{ + {"start", "Split Decision"}, + {"r1m1", "Deviant's Domain"}, + {"r1m2", "Dread Portal"}, + {"r1m3", "Judgement Call"}, + {"r1m4", "Cave of Death"}, + {"r1m5", "Towers of Wrath"}, + {"r1m6", "Temple of Pain"}, + {"r1m7", "Tomb of the Overlord"}, + {"r2m1", "Tempus Fugit"}, + {"r2m2", "Elemental Fury I"}, + {"r2m3", "Elemental Fury II"}, + {"r2m4", "Curse of Osiris"}, + {"r2m5", "Wizard's Keep"}, + {"r2m6", "Blood Sacrifice"}, + {"r2m7", "Last Bastion"}, + {"r2m8", "Source of Evil"}, + {"ctf1", "Division of Change"} +}; + +typedef struct +{ + char *description; + int firstLevel; + int levels; +} episode_t; + +episode_t episodes[] = +{ + {"Welcome to Quake", 0, 1}, + {"Doomed Dimension", 1, 8}, + {"Realm of Black Magic", 9, 7}, + {"Netherworld", 16, 7}, + {"The Elder World", 23, 8}, + {"Final Level", 31, 1}, + {"Deathmatch Arena", 32, 6} +}; + +//MED 01/06/97 added hipnotic episodes +episode_t hipnoticepisodes[] = +{ + {"Scourge of Armagon", 0, 1}, + {"Fortress of the Dead", 1, 5}, + {"Dominion of Darkness", 6, 6}, + {"The Rift", 12, 4}, + {"Final Level", 16, 1}, + {"Deathmatch Arena", 17, 1} +}; + +//PGM 01/07/97 added rogue episodes +//PGM 03/02/97 added dmatch episode +episode_t rogueepisodes[] = +{ + {"Introduction", 0, 1}, + {"Hell's Fortress", 1, 7}, + {"Corridors of Time", 8, 8}, + {"Deathmatch Arena", 16, 1} +}; + +int startepisode; +int startlevel; +int maxplayers; +qboolean m_serverInfoMessage = false; +double m_serverInfoMessageTime; + +void M_Menu_GameOptions_f (void) +{ + key_dest = key_menu; + m_state = m_gameoptions; + m_entersound = true; + if (maxplayers == 0) + maxplayers = svs.maxclients; + if (maxplayers < 2) + maxplayers = svs.maxclientslimit; +} + + +int gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 112, 120}; +#define NUM_GAMEOPTIONS 9 +int gameoptions_cursor; + +void M_GameOptions_Draw (void) +{ + qpic_t *p; + int x; + + // M_DrawTransPic (16, 4, Draw_CachePic ("gfx/qplaque.lmp") ); + p = Draw_CachePic ("gfx/p_multi.lmp"); + M_DrawPic ( (/*320*/min_vid_width-p->width)/2, 4, p); + + M_DrawTextBox (152, 32, 10, 1); + M_Print (160, 40, "begin game"); + + M_Print (0, 56, " Max players"); + M_Print (160, 56, va("%i", maxplayers) ); + + M_Print (0, 64, " Game Type"); + if (coop.value) + M_Print (160, 64, "Cooperative"); + else + M_Print (160, 64, "Deathmatch"); + + M_Print (0, 72, " Teamplay"); + if (rogue) + { + char *msg; + + switch((int)teamplay.value) + { + case 1: msg = "No Friendly Fire"; break; + case 2: msg = "Friendly Fire"; break; + case 3: msg = "Tag"; break; + case 4: msg = "Capture the Flag"; break; + case 5: msg = "One Flag CTF"; break; + case 6: msg = "Three Team CTF"; break; + default: msg = "Off"; break; + } + M_Print (160, 72, msg); + } + else + { + char *msg; + + switch((int)teamplay.value) + { + case 1: msg = "No Friendly Fire"; break; + case 2: msg = "Friendly Fire"; break; + default: msg = "Off"; break; + } + M_Print (160, 72, msg); + } + + M_Print (0, 80, " Skill"); + if (skill.value == 0) + M_Print (160, 80, "Easy difficulty"); + else if (skill.value == 1) + M_Print (160, 80, "Normal difficulty"); + else if (skill.value == 2) + M_Print (160, 80, "Hard difficulty"); + else + M_Print (160, 80, "Nightmare difficulty"); + + M_Print (0, 88, " Frag Limit"); + if (fraglimit.value == 0) + M_Print (160, 88, "none"); + else + M_Print (160, 88, va("%i frags", (int)fraglimit.value)); + + M_Print (0, 96, " Time Limit"); + if (timelimit.value == 0) + M_Print (160, 96, "none"); + else + M_Print (160, 96, va("%i minutes", (int)timelimit.value)); + + M_Print (0, 112, " Episode"); + //MED 01/06/97 added hipnotic episodes + if (r2_mod == 1) + M_Print (160, 112, hipnoticepisodes[startepisode].description); + //PGM 01/07/97 added rogue episodes + else if (r2_mod == 2) + M_Print (160, 112, rogueepisodes[startepisode].description); + else + M_Print (160, 112, episodes[startepisode].description); + + M_Print (0, 120, " Level"); + //MED 01/06/97 added hipnotic episodes + if (r2_mod == 1) + { + M_Print (160, 120, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].description); + M_Print (160, 128, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name); + } + //PGM 01/07/97 added rogue episodes + else if (r2_mod == 2) + { + M_Print (160, 120, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].description); + M_Print (160, 128, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name); + } + else + { + M_Print (160, 120, levels[episodes[startepisode].firstLevel + startlevel].description); + M_Print (160, 128, levels[episodes[startepisode].firstLevel + startlevel].name); + } + +// line cursor + M_DrawCharacter (144, gameoptions_cursor_table[gameoptions_cursor], 12+((int)(realtime*4)&1)); + + if (m_serverInfoMessage) + { + if ((realtime - m_serverInfoMessageTime) < 5.0) + { + x = (/*320*/min_vid_width-26*8)/2; + M_DrawTextBox (x, 138, 24, 4); + x += 8; + M_Print (x, 146, " More than 4 players "); + M_Print (x, 154, " requires using command "); + M_Print (x, 162, "line parameters; please "); + M_Print (x, 170, " see techinfo.txt. "); + } + else + { + m_serverInfoMessage = false; + } + } +} + + +void M_NetStart_Change (int dir) +{ + int count; + + switch (gameoptions_cursor) + { + case 1: + maxplayers += dir; + if (maxplayers > svs.maxclientslimit) + { + maxplayers = svs.maxclientslimit; + m_serverInfoMessage = true; + m_serverInfoMessageTime = realtime; + } + if (maxplayers < 2) + maxplayers = 2; + break; + + case 2: + Cvar_SetValue ("coop", (float)(coop.value ? 0 : 1)); + break; + + case 3: + if (rogue) + count = 6; + else + count = 2; + + Cvar_SetValue ("teamplay", teamplay.value + dir); + if (teamplay.value > count) + Cvar_SetValue ("teamplay", 0); + else if (teamplay.value < 0) + Cvar_SetValue ("teamplay", (float)count); + break; + + case 4: + Cvar_SetValue ("skill", skill.value + dir); + if (skill.value > 3) + Cvar_SetValue ("skill", 0); + if (skill.value < 0) + Cvar_SetValue ("skill", 3); + break; + + case 5: + Cvar_SetValue ("fraglimit", fraglimit.value + dir*10); + if (fraglimit.value > 100) + Cvar_SetValue ("fraglimit", 0); + if (fraglimit.value < 0) + Cvar_SetValue ("fraglimit", 100); + break; + + case 6: + Cvar_SetValue ("timelimit", timelimit.value + dir*5); + if (timelimit.value > 60) + Cvar_SetValue ("timelimit", 0); + if (timelimit.value < 0) + Cvar_SetValue ("timelimit", 60); + break; + + case 7: + startepisode += dir; + //MED 01/06/97 added hipnotic count + if (r2_mod == 1) + count = 6; + //PGM 01/07/97 added rogue count + //PGM 03/02/97 added 1 for dmatch episode + else if (r2_mod == 2) + count = 4; + else if (registered.value) + count = 7; + else + count = 2; + + if (startepisode < 0) + startepisode = count - 1; + + if (startepisode >= count) + startepisode = 0; + + startlevel = 0; + break; + + case 8: + startlevel += dir; + //MED 01/06/97 added hipnotic episodes + if (r2_mod == 1) + count = hipnoticepisodes[startepisode].levels; + //PGM 01/06/97 added hipnotic episodes + else if (r2_mod == 2) + count = rogueepisodes[startepisode].levels; + else + count = episodes[startepisode].levels; + + if (startlevel < 0) + startlevel = count - 1; + + if (startlevel >= count) + startlevel = 0; + break; + } +} + +void M_GameOptions_Key (int key) +{ + switch (key) + { + case K_ESCAPE: + case K_ALT: + M_Menu_Net_f (); + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + gameoptions_cursor--; + if (gameoptions_cursor < 0) + gameoptions_cursor = NUM_GAMEOPTIONS-1; + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + gameoptions_cursor++; + if (gameoptions_cursor >= NUM_GAMEOPTIONS) + gameoptions_cursor = 0; + break; + + case K_LEFTARROW: + if (gameoptions_cursor == 0) + break; + S_LocalSound ("misc/menu3.wav"); + M_NetStart_Change (-1); + break; + + case K_RIGHTARROW: + if (gameoptions_cursor == 0) + break; + S_LocalSound ("misc/menu3.wav"); + M_NetStart_Change (1); + break; + case K_CTRL: + case K_MOUSE1: + S_LocalSound ("misc/menu2.wav"); + if (gameoptions_cursor == 0) + { + if (sv.active) + Cbuf_AddText ("disconnect\n"); + Cbuf_AddText ("listen 0\n"); // so host_netport will be re-examined + Cbuf_AddText ( va ("maxplayers %u\n", maxplayers) ); + SCR_BeginLoadingPlaque (); + + if (r2_mod == 1) + Cbuf_AddText ( va ("map %s\n", hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name) ); + else if (r2_mod == 2) + Cbuf_AddText ( va ("map %s\n", roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name) ); + else + Cbuf_AddText ( va ("map %s\n", levels[episodes[startepisode].firstLevel + startlevel].name) ); + + return; + } + + M_NetStart_Change (1); + break; + } +} + +//============================================================================= +/* SEARCH MENU */ + +qboolean searchComplete = false; +double searchCompleteTime; + +void M_Menu_Search_f (void) +{ + key_dest = key_menu; + m_state = m_search; + m_entersound = false; + slistSilent = true; + slistLocal = false; + searchComplete = false; + NET_Slist_f(); + +} + +void M_Search_Draw (void) +{ + qpic_t *p; + int x; + + p = Draw_CachePic ("gfx/p_multi.lmp"); + M_DrawPic ( (/*320*/min_vid_width-p->width)/2, 4, p); + x = (/*320*/min_vid_width/2) - ((12*8)/2) + 4; + M_DrawTextBox (x-8, 32, 12, 1); + M_Print (x, 40, "Searching..."); + + if(slistInProgress) + { + NET_Poll(); + return; + } + + if (! searchComplete) + { + searchComplete = true; + searchCompleteTime = realtime; + } + + if (hostCacheCount) + { + M_Menu_ServerList_f (); + return; + } + + M_PrintWhite ((/*320*/min_vid_width/2) - ((22*8)/2), 64, "No Quake servers found"); + if ((realtime - searchCompleteTime) < 3.0) + return; + + M_Menu_LanConfig_f (); +} + + +void M_Search_Key (int key) +{ +} + +//============================================================================= +/* SERVER LIST MENU */ + +#define MENU_X 50 +#define MENU_Y 21 +#define TITLE_Y 4 +#define STAT_Y 166 + +int slist_cursor = 0, slist_mins = 0, slist_maxs = 15, slist_state; + +void M_Menu_ServerList_f (void) +{ + key_dest = key_menu; + m_state = m_slist; + m_entersound = true; + slist_state = 0; +} + +void M_ServerList_Draw (void) { + int serv, line; + + // M_DrawTransPic (16, 4, Draw_CachePic("gfx/qplaque.lmp")); + M_DrawTextBox (MENU_X, TITLE_Y, 23, 1); + M_PrintWhite (MENU_X + 60, TITLE_Y + 8, "Server List"); + + if (!slist[0].server) { + M_PrintWhite (84, MENU_Y + 16 + 16, "Empty server list"); + M_Print (40, MENU_Y + 192, "Press Y-Button to add a server"); + return; + } + + M_DrawTextBox (MENU_X, STAT_Y, 23, 1); + M_DrawTextBox (MENU_X, MENU_Y, 23, slist_maxs - slist_mins + 1); + for (serv = slist_mins, line = 1 ; serv <= slist_maxs && serv < MAX_SERVER_LIST && slist[serv].server ; serv++, line++) + M_Print (MENU_X + 18, line * 8 + MENU_Y, va("%1.21s", slist[serv].description)); + M_Print (40, MENU_Y + 192, "Press Y-Button to add a server"); + M_Print (28, MENU_Y + 200, "Press X-Button to remove a server"); + M_PrintWhite (MENU_X + 18, STAT_Y + 8, va("%1.22s", slist[slist_cursor].server)); + M_DrawCharacter (MENU_X + 8, (slist_cursor - slist_mins + 1) * 8 + MENU_Y, 12+((int)(realtime*4)&1)); +} + +void M_ServerList_Key (key) { + int slist_length; + + //if (!slist[0].server && key != K_ESCAPE && key != K_INS) + // return; + + switch (key) { + case K_ESCAPE: + case K_ALT: + M_Menu_MultiPlayer_f (); + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + if (slist_cursor > 0) { + SList_Switch (slist_cursor, slist_cursor - 1); + slist_cursor--; + } + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + if (slist_cursor != SList_Length() - 1) { + SList_Switch (slist_cursor, slist_cursor + 1); + slist_cursor++; + } + else if (slist_cursor < MAX_SERVER_LIST - 1 && slist[slist_cursor+1].server) + slist_cursor++; + break; + + case K_HOME: + S_LocalSound ("misc/menu1.wav"); + slist_cursor = 0; + break; + + case K_END: + S_LocalSound ("misc/menu1.wav"); + slist_cursor = SList_Length() - 1; + break; + + case K_MOUSE1: + case K_CTRL: + m_state = m_main; + M_ToggleMenu_f (); + Cbuf_AddText (va("connect \"%s\"\n", slist[slist_cursor].server)); + break; + + case K_SHIFT: + S_LocalSound ("misc/menu2.wav"); + if ((slist_length = SList_Length()) < MAX_SERVER_LIST) { + if (slist_length > 0) { + if (slist_cursor < slist_length - 1) + memmove (&slist[slist_cursor+2], &slist[slist_cursor+1], (slist_length - slist_cursor - 1) * sizeof(slist[0])); + SList_Reset_NoFree (slist_cursor + 1); + SList_Set (slist_cursor + 1, "127.0.0.1", ""); + if (slist_length) + slist_cursor++; + } else { + memmove (&slist[slist_cursor+1], &slist[slist_cursor], (slist_length - slist_cursor) * sizeof(slist[0])); + SList_Reset_NoFree (slist_cursor); + SList_Set (slist_cursor, "127.0.0.1", ""); + } + } + break; + + case K_SPACE: + S_LocalSound("misc/menu2.wav"); + if ((slist_length = SList_Length()) > 0) { + SList_Reset (slist_cursor); + if (slist_cursor > 0 && slist_length - 1 == slist_cursor) { + slist_cursor--; + } else { + memmove (&slist[slist_cursor], &slist[slist_cursor+1], (slist_length - slist_cursor - 1) * sizeof(slist[0])); + SList_Reset_NoFree (slist_length - 1); + } + } + break; + } + + if (slist_cursor < slist_mins) { + slist_maxs -= (slist_mins - slist_cursor); + slist_mins = slist_cursor; + } + + if (slist_cursor > slist_maxs) { + slist_mins += (slist_cursor - slist_maxs); + slist_maxs = slist_cursor; + } +} + +//============================================================================= +/* Menu Subsystem */ + + +void M_Init (void) +{ + Cmd_AddCommand ("togglemenu", M_ToggleMenu_f); + + Cmd_AddCommand ("menu_main", M_Menu_Main_f); + Cmd_AddCommand ("menu_singleplayer", M_Menu_SinglePlayer_f); + Cmd_AddCommand ("menu_load", M_Menu_Load_f); + Cmd_AddCommand ("menu_save", M_Menu_Save_f); + Cmd_AddCommand ("menu_multiplayer", M_Menu_MultiPlayer_f); + Cmd_AddCommand ("menu_setup", M_Menu_Setup_f); + Cmd_AddCommand ("menu_namemaker", M_Menu_NameMaker_f); + Cmd_AddCommand ("menu_options", M_Menu_Options_f); + Cmd_AddCommand ("menu_keys", M_Menu_Keys_f); + Cmd_AddCommand ("menu_video", M_Menu_Video_f); + Cmd_AddCommand ("help", M_Menu_Help_f); + Cmd_AddCommand ("menu_quit", M_Menu_Quit_f); + Cmd_AddCommand ("menu_serverlist", M_Menu_ServerList_f); +} + + +void M_Draw (void) +{ + if (m_state == m_none || key_dest != key_menu) + return; + + if (!m_recursiveDraw) + { + scr_copyeverything = 1; + + if (scr_con_current) + { + Draw_ConsoleBackground (vid.height); + VID_UnlockBuffer (); + S_ExtraUpdate (); + VID_LockBuffer (); + } + else + Draw_FadeScreen (); + + scr_fullupdate = 0; + } + else + { + m_recursiveDraw = false; + } + + switch (m_state) + { + case m_none: + break; + + case m_main: + M_Main_Draw (); + break; + + case m_singleplayer: + M_SinglePlayer_Draw (); + break; + + case m_load: + M_Load_Draw (); + break; + + case m_save: + M_Save_Draw (); + break; + + case m_multiplayer: + M_MultiPlayer_Draw (); + break; + + case m_setup: + M_Setup_Draw (); + break; + + case m_namemaker: + M_NameMaker_Draw (); + break; + + case m_net: + M_Net_Draw (); + break; + + case m_options: + M_Options_Draw (); + break; + + case m_keys: + M_Keys_Draw (); + break; + + case m_video: + M_Video_Draw (); + break; + + case m_help: + M_Help_Draw (); + break; + + case m_quit: + M_Quit_Draw (); + break; + + case m_serialconfig: + M_SerialConfig_Draw (); + break; + + case m_modemconfig: + M_ModemConfig_Draw (); + break; + + case m_lanconfig: + M_LanConfig_Draw (); + break; + + case m_gameoptions: + M_GameOptions_Draw (); + break; + + case m_search: + M_Search_Draw (); + break; + + case m_slist: + M_ServerList_Draw (); + break; + } + + if (m_entersound) + { + S_LocalSound ("misc/menu2.wav"); + m_entersound = false; + } + + VID_UnlockBuffer (); + S_ExtraUpdate (); + VID_LockBuffer (); +} + + +void M_Keydown (int key) +{ + //Dan: + // if (!bind_grab&&key==K_JOY1) key=K_MOUSE1; + switch (m_state) + { + case m_none: + return; + + case m_main: + M_Main_Key (key); + return; + + case m_singleplayer: + M_SinglePlayer_Key (key); + return; + + case m_load: + M_Load_Key (key); + return; + + case m_save: + M_Save_Key (key); + return; + + case m_multiplayer: + M_MultiPlayer_Key (key); + return; + + case m_setup: + M_Setup_Key (key); + return; + + case m_namemaker: + M_NameMaker_Key (key); + return; + + case m_net: + M_Net_Key (key); + return; + + case m_options: + M_Options_Key (key); + return; + + case m_keys: + M_Keys_Key (key); + return; + + case m_video: + M_Video_Key (key); + return; + + case m_help: + M_Help_Key (key); + return; + + case m_quit: + M_Quit_Key (key); + return; + + case m_serialconfig: + M_SerialConfig_Key (key); + return; + + case m_modemconfig: + M_ModemConfig_Key (key); + return; + + case m_lanconfig: + M_LanConfig_Key (key); + return; + + case m_gameoptions: + M_GameOptions_Key (key); + return; + + case m_search: + M_Search_Key (key); + break; + + case m_slist: + M_ServerList_Key (key); + return; + } +} + + +void M_ConfigureNetSubsystem(void) +{ +// enable/disable net systems to match desired config + + Cbuf_AddText ("stopdemo\n"); + if (SerialConfig || DirectConfig) + { + Cbuf_AddText ("com1 enable\n"); + } + + if (IPXConfig || TCPIPConfig) + net_hostport = lanConfig_port; +} diff --git a/project/jni/application/quake/source/menu.h b/project/jni/application/quake/source/menu.h new file mode 100644 index 000000000..5883d8294 --- /dev/null +++ b/project/jni/application/quake/source/menu.h @@ -0,0 +1,36 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// +// the net drivers should just set the apropriate bits in m_activenet, +// instead of having the menu code look through their internal tables +// +#define MNET_IPX 1 +#define MNET_TCP 2 + +extern int m_activenet; + +// +// menus +// +void M_Init (void); +void M_Keydown (int key); +void M_Draw (void); +void M_ToggleMenu_f (void); diff --git a/project/jni/application/quake/source/model.c b/project/jni/application/quake/source/model.c new file mode 100644 index 000000000..ddfe11aac --- /dev/null +++ b/project/jni/application/quake/source/model.c @@ -0,0 +1,3498 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// models.c -- model loading and caching + +// models are the only shared resource between a client and server running +// on the same machine. + +#include "quakedef.h" +#include "r_local.h" + +model_t *loadmodel; +char loadname[32]; // for hunk tags + +#ifdef USEFPM +model_FPM_t *loadmodelFPM; +#endif + +void Mod_LoadSpriteModel (model_t *mod, void *buffer); +void Mod_LoadBrushModel (model_t *mod, void *buffer); +void Mod_LoadAliasModel (model_t *mod, void *buffer); +model_t *Mod_LoadModel (model_t *mod, qboolean crash); + +#ifdef USEFPM +void Mod_LoadSpriteModelFPM (model_FPM_t *mod, void *buffer); +void Mod_LoadBrushModelFPM (model_FPM_t *mod, void *buffer); +void Mod_LoadAliasModelFPM (model_FPM_t *mod, void *buffer); +model_FPM_t *Mod_LoadModelFPM (model_FPM_t *mod, qboolean crash); +#endif + +byte mod_novis[MAX_MAP_LEAFS/8]; + +#define MAX_MOD_KNOWN 256 +model_t mod_known[MAX_MOD_KNOWN]; +int mod_numknown; + +#ifdef USEFPM +model_FPM_t mod_knownFPM[MAX_MOD_KNOWN]; +#endif + +// values for model_t's needload +#define NL_PRESENT 0 +#define NL_NEEDS_LOADED 1 +#define NL_UNREFERENCED 2 + +#ifdef DEBUG +#include "LogFloat.h" +#endif + +/* +=============== +Mod_Init +=============== +*/ +void Mod_Init (void) +{ + Q_memset (mod_novis, 0xff, sizeof(mod_novis)); +} + +/* +=============== +Mod_Extradata + +Caches the data if needed +=============== +*/ +void *Mod_Extradata (model_t *mod) +{ + void *r; + + r = Cache_Check (&mod->cache); + if (r) + return r; + + Mod_LoadModel (mod, true); + + if (!mod->cache.data) + Sys_Error ("Mod_Extradata: caching failed"); + return mod->cache.data; +} + +#ifdef USEFPM +void *Mod_ExtradataFPM (model_FPM_t *mod) +{ + void *r; + + r = Cache_Check (&mod->cache); + if (r) + return r; + + Mod_LoadModelFPM ((model_FPM_t *)mod, true); + + if (!mod->cache.data) + Sys_Error ("Mod_Extradata: caching failed"); + return mod->cache.data; +} +#endif + +/* +=============== +Mod_PointInLeaf +=============== +*/ +mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model) +{ + mnode_t *node; + float d; + mplane_t *plane; + + if (!model || !model->nodes) + Sys_Error ("Mod_PointInLeaf: bad model"); + + node = model->nodes; + while (1) + { + if (node->contents < 0) + return (mleaf_t *)node; + plane = node->plane; + d = DotProduct (p,plane->normal) - plane->dist; + if (d > 0) + node = node->children[0]; + else + node = node->children[1]; + } + + return NULL; // never reached +} + +#ifdef USEFPM +mleaf_FPM_t *Mod_PointInLeafFPM (vec3_FPM_t p, model_FPM_t *model) +{ + mnode_FPM_t *node; + fixedpoint_t d; + mplane_FPM_t *plane; + + if (!model || !model->nodes) + Sys_Error ("Mod_PointInLeaf: bad model"); + + node = model->nodes; + while (1) + { + if (node->contents < 0) + return (mleaf_FPM_t *)node; + plane = node->plane; + d = FPM_SUB(DotProductFPM (p,plane->normal), plane->dist); + if (d > 0) + node = node->children[0]; + else + node = node->children[1]; + } + + return NULL; // never reached +} +#endif + +/* +=================== +Mod_DecompressVis +=================== +*/ +byte *Mod_DecompressVis (byte *in, model_t *model) +{ + static byte decompressed[MAX_MAP_LEAFS/8]; + int c; + byte *out; + int row; + + row = (model->numleafs+7)>>3; + out = decompressed; + + if (!in) + { // no vis info, so make all visible + while (row) + { + *out++ = 0xff; + row--; + } + return decompressed; + } + + do + { + if (*in) + { + *out++ = *in++; + continue; + } + + c = in[1]; + in += 2; + while (c) + { + *out++ = 0; + c--; + } + } while (out - decompressed < row); + + return decompressed; +} + + +#ifdef USEFPM +byte *Mod_DecompressVisFPM (byte *in, model_FPM_t *model) +{ + static byte decompressed[MAX_MAP_LEAFS/8]; + int c; + byte *out; + int row; + + row = (model->numleafs+7)>>3; + out = decompressed; + + if (!in) + { // no vis info, so make all visible + while (row) + { + *out++ = 0xff; + row--; + } + return decompressed; + } + + do + { + if (*in) + { + *out++ = *in++; + continue; + } + + c = in[1]; + in += 2; + while (c) + { + *out++ = 0; + c--; + } + } while (out - decompressed < row); + + return decompressed; +} +#endif + +byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model) +{ + if (leaf == model->leafs) + return mod_novis; + return Mod_DecompressVis (leaf->compressed_vis, model); +} + +#ifdef USEFPM +byte *Mod_LeafPVSFPM (mleaf_FPM_t *leaf, model_FPM_t *model) +{ + if (leaf == model->leafs) + return mod_novis; + return Mod_DecompressVisFPM (leaf->compressed_vis, model); +} +#endif + +/* +=================== +Mod_ClearAll +=================== +*/ +void Mod_ClearAll (void) +{ + int i; + model_t *mod; + + + for (i=0 , mod=mod_known ; ineedload = NL_UNREFERENCED; +//FIX FOR CACHE_ALLOC ERRORS: + if (mod->type == mod_sprite) mod->cache.data = NULL; + } +} + +#ifdef USEFPM +void Mod_ClearAllFPM (void) +{ + int i; + model_FPM_t *mod; + + + for (i=0 , mod=mod_knownFPM ; ineedload = NL_UNREFERENCED; +//FIX FOR CACHE_ALLOC ERRORS: + if (mod->type == mod_sprite) mod->cache.data = NULL; + } +} +#endif + +/* +================== +Mod_FindName + +================== +*/ +model_t *Mod_FindName (char *name) +{ + int i; + model_t *mod; + model_t *avail = NULL; + + if (!name[0]) + Sys_Error ("Mod_ForName: NULL name"); + +// +// search the currently loaded models +// + for (i=0 , mod=mod_known ; iname, name) ) + break; + if (mod->needload == NL_UNREFERENCED) + if (!avail || mod->type != mod_alias) + avail = mod; + } + + if (i == mod_numknown) + { + if (mod_numknown == MAX_MOD_KNOWN) + { + if (avail) + { + mod = avail; + if (mod->type == mod_alias) + if (Cache_Check (&mod->cache)) + Cache_Free (&mod->cache); + } + else + Sys_Error ("mod_numknown == MAX_MOD_KNOWN"); + } + else + mod_numknown++; + strcpy (mod->name, name); + mod->needload = NL_NEEDS_LOADED; + } + + return mod; +} + +#ifdef USEFPM +model_FPM_t *Mod_FindNameFPM (char *name) +{ + int i; + model_FPM_t *mod; + model_FPM_t *avail = NULL; + + if (!name[0]) + Sys_Error ("Mod_ForName: NULL name"); + +// +// search the currently loaded models +// + for (i=0 , mod=mod_knownFPM ; iname, name) ) + break; + if (mod->needload == NL_UNREFERENCED) + if (!avail || mod->type != mod_alias) + avail = mod; + } + + if (i == mod_numknown) + { + if (mod_numknown == MAX_MOD_KNOWN) + { + if (avail) + { + mod = avail; + if (mod->type == mod_alias) + if (Cache_Check (&mod->cache)) + Cache_Free (&mod->cache); + } + else + Sys_Error ("mod_numknown == MAX_MOD_KNOWN"); + } + else + mod_numknown++; + strcpy (mod->name, name); + mod->needload = NL_NEEDS_LOADED; + } + + return mod; +} +#endif + +/* +================== +Mod_TouchModel + +================== +*/ +void Mod_TouchModel (char *name) +{ + model_t *mod; + + mod = Mod_FindName (name); + + if (mod->needload == NL_PRESENT) + { + if (mod->type == mod_alias) + Cache_Check (&mod->cache); + } +} + +#ifdef USEFPM +void Mod_TouchModelFPM (char *name) +{ + model_FPM_t *mod; + + mod = Mod_FindNameFPM (name); + + if (mod->needload == NL_PRESENT) + { + if (mod->type == mod_alias) + Cache_Check (&mod->cache); + } +} +#endif + +/* +================== +Mod_LoadModel + +Loads a model into the cache +================== +*/ +model_t *Mod_LoadModel (model_t *mod, qboolean crash) +{ + unsigned *buf; + byte stackbuf[1024]; // avoid dirtying the cache heap + + if (mod->type == mod_alias) + { + if (Cache_Check (&mod->cache)) + { + mod->needload = NL_PRESENT; + return mod; + } + } + else + { + if (mod->needload == NL_PRESENT) + return mod; + } + +// +// because the world is so huge, load it one piece at a time +// + +// +// load the file +// + buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf)); + if (!buf) + { + if (crash) + Sys_Error ("Mod_NumForName: %s not found", mod->name); + return NULL; + } + +// +// allocate a new model +// + COM_FileBase (mod->name, loadname); + + loadmodel = mod; + +// +// fill it in +// + +// call the apropriate loader + mod->needload = NL_PRESENT; + + switch (LittleLong(*(unsigned *)buf)) + { + case IDPOLYHEADER: + Mod_LoadAliasModel (mod, buf); + break; + + case IDSPRITEHEADER: + Mod_LoadSpriteModel (mod, buf); + break; + + default: + Mod_LoadBrushModel (mod, buf); + break; + } + + return mod; +} + +#ifdef USEFPM +model_FPM_t *Mod_LoadModelFPM (model_FPM_t *mod, qboolean crash) +{ + unsigned *buf; + byte stackbuf[1024]; // avoid dirtying the cache heap + + if (mod->type == mod_alias) + { + if (Cache_Check (&mod->cache)) + { + mod->needload = NL_PRESENT; + return mod; + } + } + else + { + if (mod->needload == NL_PRESENT) + return mod; + } + +// +// because the world is so huge, load it one piece at a time +// + +// +// load the file +// + buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf)); + if (!buf) + { + if (crash) + Sys_Error ("Mod_NumForName: %s not found", mod->name); + return NULL; + } + +// +// allocate a new model +// + COM_FileBase (mod->name, loadname); + + loadmodelFPM = mod; + +// +// fill it in +// + +// call the apropriate loader + mod->needload = NL_PRESENT; + + switch (LittleLong(*(unsigned *)buf)) + { + case IDPOLYHEADER: + Mod_LoadAliasModelFPM (mod, buf); + break; + + case IDSPRITEHEADER: + Mod_LoadSpriteModelFPM (mod, buf); + break; + + default: + Mod_LoadBrushModelFPM (mod, buf); + break; + } + + return mod; +} +#endif + +/* +================== +Mod_ForName + +Loads in a model for the given name +================== +*/ +model_t *Mod_ForName (char *name, qboolean crash) +{ + model_t *mod; + + mod = Mod_FindName (name); + + return Mod_LoadModel (mod, crash); +} + +#ifdef USEFPM +model_FPM_t *Mod_ForNameFPM (char *name, qboolean crash) +{ + model_FPM_t *mod; + + mod = Mod_FindNameFPM (name); + + return Mod_LoadModelFPM (mod, crash); +} +#endif + +/* +=============================================================================== + + BRUSHMODEL LOADING + +=============================================================================== +*/ + +byte *mod_base; + + +/* +================= +Mod_LoadTextures +================= +*/ +void Mod_LoadTextures (lump_t *l) +{ + int i, j, pixels, num, max, altmax; + miptex_t *mt; + texture_t *tx, *tx2; + texture_t *anims[10]; + texture_t *altanims[10]; + dmiptexlump_t *m; + + if (!l->filelen) + { + loadmodel->textures = NULL; + return; + } + m = (dmiptexlump_t *)(mod_base + l->fileofs); + + m->nummiptex = LittleLong (m->nummiptex); + + loadmodel->numtextures = m->nummiptex; + loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures), loadname); + + + + for (i=0 ; inummiptex ; i++) + { + m->dataofs[i] = LittleLong(m->dataofs[i]); + if (m->dataofs[i] == -1) + continue; + mt = (miptex_t *)((byte *)m + m->dataofs[i]); + mt->width = LittleLong (mt->width); + mt->height = LittleLong (mt->height); + for (j=0 ; joffsets[j] = LittleLong (mt->offsets[j]); + + if ( (mt->width & 15) || (mt->height & 15) ) + Sys_Error ("Texture %s is not 16 aligned", mt->name); + pixels = mt->width*mt->height/64*85; + tx = Hunk_AllocName (sizeof(texture_t) +pixels, loadname ); + loadmodel->textures[i] = tx; + + Q_memcpy (tx->name, mt->name, sizeof(tx->name)); + tx->width = mt->width; + tx->height = mt->height; + for (j=0 ; joffsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t); + // the pixels immediately follow the structures + Q_memcpy ( tx+1, mt+1, pixels); + + if (!Q_strncmp(mt->name,"sky",3)) + R_InitSky (tx); + } + +// +// sequence the animations +// + for (i=0 ; inummiptex ; i++) + { + tx = loadmodel->textures[i]; + if (!tx || tx->name[0] != '+') + continue; + if (tx->anim_next) + continue; // allready sequenced + + // find the number of frames in the animation + Q_memset (anims, 0, sizeof(anims)); + Q_memset (altanims, 0, sizeof(altanims)); + + max = tx->name[1]; + altmax = 0; + if (max >= 'a' && max <= 'z') + max -= 'a' - 'A'; + if (max >= '0' && max <= '9') + { + max -= '0'; + altmax = 0; + anims[max] = tx; + max++; + } + else if (max >= 'A' && max <= 'J') + { + altmax = max - 'A'; + max = 0; + altanims[altmax] = tx; + altmax++; + } + else + Sys_Error ("Bad animating texture %s", tx->name); + + for (j=i+1 ; jnummiptex ; j++) + { + tx2 = loadmodel->textures[j]; + if (!tx2 || tx2->name[0] != '+') + continue; + if (strcmp (tx2->name+2, tx->name+2)) + continue; + + num = tx2->name[1]; + if (num >= 'a' && num <= 'z') + num -= 'a' - 'A'; + if (num >= '0' && num <= '9') + { + num -= '0'; + anims[num] = tx2; + if (num+1 > max) + max = num + 1; + } + else if (num >= 'A' && num <= 'J') + { + num = num - 'A'; + altanims[num] = tx2; + if (num+1 > altmax) + altmax = num+1; + } + else + Sys_Error ("Bad animating texture %s", tx->name); + } + +#define ANIM_CYCLE 2 + // link them all together + for (j=0 ; jname); + tx2->anim_total = max * ANIM_CYCLE; + tx2->anim_min = j * ANIM_CYCLE; + tx2->anim_max = (j+1) * ANIM_CYCLE; + tx2->anim_next = anims[ (j+1)%max ]; + if (altmax) + tx2->alternate_anims = altanims[0]; + } + for (j=0 ; jname); + tx2->anim_total = altmax * ANIM_CYCLE; + tx2->anim_min = j * ANIM_CYCLE; + tx2->anim_max = (j+1) * ANIM_CYCLE; + tx2->anim_next = altanims[ (j+1)%altmax ]; + if (max) + tx2->alternate_anims = anims[0]; + } + } +} + +#ifdef USEFPM +void Mod_LoadTexturesFPM (lump_t *l) +{ + int i, j, pixels, num, max, altmax; + miptex_t *mt; + texture_t *tx, *tx2; + texture_t *anims[10]; + texture_t *altanims[10]; + dmiptexlump_t *m; + + if (!l->filelen) + { + loadmodelFPM->textures = NULL; + return; + } + m = (dmiptexlump_t *)(mod_base + l->fileofs); + + m->nummiptex = LittleLong (m->nummiptex); + + loadmodelFPM->numtextures = m->nummiptex; + loadmodelFPM->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodelFPM->textures) , loadname); + + for (i=0 ; inummiptex ; i++) + { + m->dataofs[i] = LittleLong(m->dataofs[i]); + if (m->dataofs[i] == -1) + continue; + mt = (miptex_t *)((byte *)m + m->dataofs[i]); + mt->width = LittleLong (mt->width); + mt->height = LittleLong (mt->height); + for (j=0 ; joffsets[j] = LittleLong (mt->offsets[j]); + + if ( (mt->width & 15) || (mt->height & 15) ) + Sys_Error ("Texture %s is not 16 aligned", mt->name); + pixels = mt->width*mt->height/64*85; + tx = Hunk_AllocName (sizeof(texture_t) +pixels, loadname ); + loadmodelFPM->textures[i] = tx; + + Q_memcpy (tx->name, mt->name, sizeof(tx->name)); + tx->width = mt->width; + tx->height = mt->height; + for (j=0 ; joffsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t); + // the pixels immediately follow the structures + Q_memcpy ( tx+1, mt+1, pixels); + + if (!Q_strncmp(mt->name,"sky",3)) + R_InitSky (tx); + } + +// +// sequence the animations +// + for (i=0 ; inummiptex ; i++) + { + tx = loadmodelFPM->textures[i]; + if (!tx || tx->name[0] != '+') + continue; + if (tx->anim_next) + continue; // allready sequenced + + // find the number of frames in the animation + Q_memset (anims, 0, sizeof(anims)); + Q_memset (altanims, 0, sizeof(altanims)); + + max = tx->name[1]; + altmax = 0; + if (max >= 'a' && max <= 'z') + max -= 'a' - 'A'; + if (max >= '0' && max <= '9') + { + max -= '0'; + altmax = 0; + anims[max] = tx; + max++; + } + else if (max >= 'A' && max <= 'J') + { + altmax = max - 'A'; + max = 0; + altanims[altmax] = tx; + altmax++; + } + else + Sys_Error ("Bad animating texture %s", tx->name); + + for (j=i+1 ; jnummiptex ; j++) + { + tx2 = loadmodelFPM->textures[j]; + if (!tx2 || tx2->name[0] != '+') + continue; + if (strcmp (tx2->name+2, tx->name+2)) + continue; + + num = tx2->name[1]; + if (num >= 'a' && num <= 'z') + num -= 'a' - 'A'; + if (num >= '0' && num <= '9') + { + num -= '0'; + anims[num] = tx2; + if (num+1 > max) + max = num + 1; + } + else if (num >= 'A' && num <= 'J') + { + num = num - 'A'; + altanims[num] = tx2; + if (num+1 > altmax) + altmax = num+1; + } + else + Sys_Error ("Bad animating texture %s", tx->name); + } + +#define ANIM_CYCLE 2 + // link them all together + for (j=0 ; jname); + tx2->anim_total = max * ANIM_CYCLE; + tx2->anim_min = j * ANIM_CYCLE; + tx2->anim_max = (j+1) * ANIM_CYCLE; + tx2->anim_next = anims[ (j+1)%max ]; + if (altmax) + tx2->alternate_anims = altanims[0]; + } + for (j=0 ; jname); + tx2->anim_total = altmax * ANIM_CYCLE; + tx2->anim_min = j * ANIM_CYCLE; + tx2->anim_max = (j+1) * ANIM_CYCLE; + tx2->anim_next = altanims[ (j+1)%altmax ]; + if (max) + tx2->alternate_anims = anims[0]; + } + } +} +#endif + +/* +================= +Mod_LoadLighting +================= +*/ +void Mod_LoadLighting (lump_t *l) +{ + if (!l->filelen) + { + loadmodel->lightdata = NULL; + return; + } + loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname); + Q_memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen); +} + +#ifdef USEFPM +void Mod_LoadLightingFPM (lump_t *l) +{ + if (!l->filelen) + { + loadmodelFPM->lightdata = NULL; + return; + } + loadmodelFPM->lightdata = Hunk_AllocName ( l->filelen, loadname); + Q_memcpy (loadmodelFPM->lightdata, mod_base + l->fileofs, l->filelen); +} +#endif + +/* +================= +Mod_LoadVisibility +================= +*/ +void Mod_LoadVisibility (lump_t *l) +{ + if (!l->filelen) + { + loadmodel->visdata = NULL; + return; + } + loadmodel->visdata = Hunk_AllocName ( l->filelen, loadname); + Q_memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen); +} + +#ifdef USEFPM +void Mod_LoadVisibilityFPM (lump_t *l) +{ + if (!l->filelen) + { + loadmodelFPM->visdata = NULL; + return; + } + loadmodelFPM->visdata = Hunk_AllocName ( l->filelen, loadname); + Q_memcpy (loadmodelFPM->visdata, mod_base + l->fileofs, l->filelen); +} +#endif + +/* +================= +Mod_LoadEntities +================= +*/ +void Mod_LoadEntities (lump_t *l) +{ + if (!l->filelen) + { + loadmodel->entities = NULL; + return; + } + loadmodel->entities = Hunk_AllocName ( l->filelen, loadname); + Q_memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen); +} + +#ifdef USEFPM +void Mod_LoadEntitiesFPM (lump_t *l) +{ + if (!l->filelen) + { + loadmodelFPM->entities = NULL; + return; + } + loadmodelFPM->entities = Hunk_AllocName ( l->filelen, loadname); + Q_memcpy (loadmodelFPM->entities, mod_base + l->fileofs, l->filelen); +} +#endif + +/* +================= +Mod_LoadVertexes +================= +*/ +void Mod_LoadVertexes (lump_t *l) +{ + dvertex_t *in; + mvertex_t *out; + int i, count; +#ifdef USE_PQ_OPT2 + mvertex_fxp_t *out2; +#endif + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->vertexes = out; + loadmodel->numvertexes = count; + +#ifdef USE_PQ_OPT2 + out2 = Hunk_AllocName ( count*sizeof(*out2), loadname); + loadmodel->vertexes_fxp = out2; +#endif + + for ( i=0 ; iposition[0] = LittleFloat (in->point[0]); + out->position[1] = LittleFloat (in->point[1]); + out->position[2] = LittleFloat (in->point[2]); +#ifdef USE_PQ_OPT2 + out2->position[0] = (int)(out->position[0]*524288.0f); //13.19 + out2->position[1] = (int)(out->position[1]*524288.0f); //13.19 + out2->position[2] = (int)(out->position[2]*524288.0f); //13.19 + out2++; +#endif +#if defined(_X86_)&&defined(DEBUG) + LogFloat(out->position[0], "model->vertexes->position", 0, -1); + LogFloat(out->position[1], "model->vertexes->position", 1, -1); + LogFloat(out->position[2], "model->vertexes->position", 2, -1); +#endif + } +} + +/* +================= +Mod_LoadSubmodels +================= +*/ +void Mod_LoadSubmodels (lump_t *l) +{ + dmodel_t *in; + dmodel_t *out; + int i, j, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->submodels = out; + loadmodel->numsubmodels = count; + + for ( i=0 ; imins[j] = LittleFloat (in->mins[j]) - 1; + out->maxs[j] = LittleFloat (in->maxs[j]) + 1; + out->origin[j] = LittleFloat (in->origin[j]); + } + for (j=0 ; jheadnode[j] = LittleLong (in->headnode[j]); + out->visleafs = LittleLong (in->visleafs); + out->firstface = LittleLong (in->firstface); + out->numfaces = LittleLong (in->numfaces); + } +} + +#ifdef USEFPM +void Mod_LoadSubmodelsFPM (lump_t *l) +{ + dmodel_t *in; + dmodel_FPM_t *out; + int i, j, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodelFPM->submodels = out; + loadmodelFPM->numsubmodels = count; + + for ( i=0 ; imins[j] = FPM_SUB(FPM_FROMFLOAT(LittleFloat (in->mins[j])), 1); + out->maxs[j] = FPM_ADD(FPM_FROMFLOAT(LittleFloat (in->maxs[j])), 1); + out->origin[j] = FPM_FROMFLOAT(LittleFloat (in->origin[j])); + } + for (j=0 ; jheadnode[j] = LittleLong (in->headnode[j]); + out->visleafs = LittleLong (in->visleafs); + out->firstface = LittleLong (in->firstface); + out->numfaces = LittleLong (in->numfaces); + } +} +#endif + +/* +================= +Mod_LoadEdges +================= +*/ +void Mod_LoadEdges (lump_t *l) +{ + dedge_t *in; + medge_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( (count + 1) * sizeof(*out), loadname); + + loadmodel->edges = out; + loadmodel->numedges = count; + + for ( i=0 ; iv[0] = (unsigned short)LittleShort(in->v[0]); + out->v[1] = (unsigned short)LittleShort(in->v[1]); + } +} + +#ifdef USEFPM +void Mod_LoadEdgesFPM (lump_t *l) +{ + dedge_t *in; + medge_t *out; + int i, count; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( (count + 1) * sizeof(*out), loadname); + + loadmodelFPM->edges = out; + loadmodelFPM->numedges = count; + + for ( i=0 ; iv[0] = (unsigned short)LittleShort(in->v[0]); + out->v[1] = (unsigned short)LittleShort(in->v[1]); + } +} +#endif + +#include "LogFloat.h" +/* +================= +Mod_LoadTexinfo +================= +*/ +void Mod_LoadTexinfo (lump_t *l) +{ + texinfo_t *in; + mtexinfo_t *out; + int i, j, count; + int miptex; + float len1, len2; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->texinfo = out; + loadmodel->numtexinfo = count; + + for ( i=0 ; ivecs[0][j] = LittleFloat (in->vecs[0][j]); + + len1 = Length (out->vecs[0]); + len2 = Length (out->vecs[1]); + + len1 = (len1 + len2)/2; + if (len1 < 0.32) + out->mipadjust = 4; + else if (len1 < 0.49) + out->mipadjust = 3; + else if (len1 < 0.99) + out->mipadjust = 2; + else + out->mipadjust = 1; +#else + float tmp[2][4]; + for (j=0 ; j<8 ; j++) { + tmp[0][j]=LittleFloat (in->vecs[0][j]); + out->vecs_fxp[0][j] = (int)(tmp[0][j]*64.0f); //26.6 + } + len1 = Length (tmp[0]); + len2 = Length (tmp[1]); + + len1 = (len1 + len2)/2; + if (len1 < 0.32) + out->mipadjust_fxp = 4; + else if (len1 < 0.49) + out->mipadjust_fxp = 3; + else if (len1 < 0.99) + out->mipadjust_fxp = 2; + else + out->mipadjust_fxp = 1; + +#endif + +#if 0 + if (len1 + len2 < 0.001) + out->mipadjust = 1; // don't crash + else + out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 ); +#endif + + miptex = LittleLong (in->miptex); + out->flags = LittleLong (in->flags); + + if (!loadmodel->textures) + { + out->texture = r_notexture_mip; // checkerboard texture + out->flags = 0; + } + else + { + if (miptex >= loadmodel->numtextures) + Sys_Error ("miptex >= loadmodel->numtextures"); + out->texture = loadmodel->textures[miptex]; + if (!out->texture) + { + out->texture = r_notexture_mip; // texture not found + out->flags = 0; + } + } + } +} + +#ifdef USEFPM +void Mod_LoadTexinfoFPM (lump_t *l) +{ + texinfo_t *in; + mtexinfo_FPM_t *out; + int i, j, count; + int miptex; + fixedpoint_t len1, len2; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodelFPM->texinfo = out; + loadmodelFPM->numtexinfo = count; + + for ( i=0 ; ivecs[0][j] = FPM_FROMFLOAT(LittleFloat (in->vecs[0][j])); + len1 = LengthFPM (out->vecs[0]); + len2 = LengthFPM (out->vecs[1]); + len1 = FPM_DIV(FPM_ADD(len1, len2), FPM_FROMLONG(2)); + if (len1 < FPM_FROMFLOAT(0.32)) + out->mipadjust = FPM_FROMLONG(4); + else if (len1 < FPM_FROMFLOAT(0.49)) + out->mipadjust = FPM_FROMLONG(3); + else if (len1 < FPM_FROMFLOAT(0.99)) + out->mipadjust = FPM_FROMLONG(2); + else + out->mipadjust = FPM_FROMLONG(1); +#if 0 + if (len1 + len2 < FPM_FROMFLOAT(0.001)) + out->mipadjust = FPM_FROMLONG(1); // don't crash + else + out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 ); //Dan: not converted +#endif + + miptex = LittleLong (in->miptex); + out->flags = LittleLong (in->flags); + + if (!loadmodelFPM->textures) + { + out->texture = r_notexture_mip; // checkerboard texture + out->flags = 0; + } + else + { + if (miptex >= loadmodelFPM->numtextures) + Sys_Error ("miptex >= loadmodel->numtextures"); + out->texture = loadmodelFPM->textures[miptex]; + if (!out->texture) + { + out->texture = r_notexture_mip; // texture not found + out->flags = 0; + } + } + } +} +#endif + +/* +================ +CalcSurfaceExtents + +Fills in s->texturemins[] and s->extents[] +================ +*/ +#ifndef USE_PQ_OPT3 +void CalcSurfaceExtents (msurface_t *s) +{ + float mins[2], maxs[2], val; + int i,j, e; + mvertex_t *v; + mtexinfo_t *tex; + int bmins[2], bmaxs[2]; + + mins[0] = mins[1] = 999999; + maxs[0] = maxs[1] = -99999; + + tex = s->texinfo; + + for (i=0 ; inumedges ; i++) + { + e = loadmodel->surfedges[s->firstedge+i]; + if (e >= 0) + v = &loadmodel->vertexes[loadmodel->edges[e].v[0]]; + else + v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]]; + + for (j=0 ; j<2 ; j++) + { + val = v->position[0] * tex->vecs[j][0] + + v->position[1] * tex->vecs[j][1] + + v->position[2] * tex->vecs[j][2] + + tex->vecs[j][3]; + if (val < mins[j]) + mins[j] = val; + if (val > maxs[j]) + maxs[j] = val; + } + } + + for (i=0 ; i<2 ; i++) + { + bmins[i] = (int)floor(mins[i]/16); + bmaxs[i] = (int)ceil(maxs[i]/16); + + s->texturemins[i] = bmins[i] * 16; + s->extents[i] = (bmaxs[i] - bmins[i]) * 16; + if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 256) + Sys_Error ("Bad surface extents"); + } +} + +#else + +void CalcSurfaceExtents_fxp (msurface_t *s) +{ + int mins_fxp[2], maxs_fxp[2], val_fxp; + int i,j, e; + mvertex_fxp_t *v; + mtexinfo_t *tex; + int bmins[2], bmaxs[2]; + + mins_fxp[0] = mins_fxp[1] = (2<<30); + maxs_fxp[0] = maxs_fxp[1] = -(2<<30); + + tex = s->texinfo; + + for (i=0 ; inumedges ; i++) + { + e = loadmodel->surfedges[s->firstedge+i]; + if (e >= 0) + v = &loadmodel->vertexes_fxp[loadmodel->edges[e].v[0]]; + else + v = &loadmodel->vertexes_fxp[loadmodel->edges[-e].v[1]]; + + for (j=0 ; j<2 ; j++) + { + //13.19 * 26.6 + val_fxp = (v->position[0] * tex->vecs_fxp[j][0])/64 + + (v->position[1] * tex->vecs_fxp[j][1])/64 + + (v->position[2] * tex->vecs_fxp[j][2])/64 + + tex->vecs_fxp[j][3]; + if (val_fxp < mins_fxp[j]) + mins_fxp[j] = val_fxp; + if (val_fxp > maxs_fxp[j]) + maxs_fxp[j] = val_fxp; + } + } + + for (i=0 ; i<2 ; i++) + { + //Dan: TODO: Floor and ceil + bmins[i] = mins_fxp[i]/(524288*16); + bmaxs[i] = maxs_fxp[i]/(524288*16); + + //bmins[i] = (int)floor(mins[i]/16); + //bmaxs[i] = (int)ceil(maxs[i]/16); + + s->texturemins[i] = bmins[i] * 16; + s->extents[i] = (bmaxs[i] - bmins[i]) * 16; + if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 256) + Sys_Error ("Bad surface extents"); + } +} +#endif +/* +================= +Mod_LoadFaces +================= +*/ +void Mod_LoadFaces (lump_t *l) +{ + dface_t *in; + msurface_t *out; + int i, count, surfnum; + int planenum, side; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->surfaces = out; + loadmodel->numsurfaces = count; + + for ( surfnum=0 ; surfnumfirstedge = LittleLong(in->firstedge); + out->numedges = LittleShort(in->numedges); + out->flags = 0; + + planenum = LittleShort(in->planenum); + side = LittleShort(in->side); + if (side) + out->flags |= SURF_PLANEBACK; + + out->plane = loadmodel->planes + planenum; + + out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo); + +#ifndef USE_PQ_OPT3 + CalcSurfaceExtents (out); +#else + CalcSurfaceExtents_fxp (out); +#endif + + // lighting info + + for (i=0 ; istyles[i] = in->styles[i]; + i = LittleLong(in->lightofs); + if (i == -1) + out->samples = NULL; + else + out->samples = loadmodel->lightdata + i; + + // set the drawing flags flag + + if (!Q_strncmp(out->texinfo->texture->name,"sky",3)) // sky + { + out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED); + continue; + } + + if (!Q_strncmp(out->texinfo->texture->name,"*",1)) // turbulent + { + out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED); + for (i=0 ; i<2 ; i++) + { + out->extents[i] = 16384; + out->texturemins[i] = -8192; + } + continue; + } + } +} + +#ifdef USEFPM +void Mod_LoadFacesFPM (lump_t *l) +{ + dface_t *in; + msurface_FPM_t *out; + int i, count, surfnum; + int planenum, side; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodelFPM->surfaces = out; + loadmodelFPM->numsurfaces = count; + + for ( surfnum=0 ; surfnumfirstedge = LittleLong(in->firstedge); + out->numedges = LittleShort(in->numedges); + out->flags = 0; + + planenum = LittleShort(in->planenum); + side = LittleShort(in->side); + if (side) + out->flags |= SURF_PLANEBACK; + + out->plane = loadmodelFPM->planes + planenum; + + out->texinfo = loadmodelFPM->texinfo + LittleShort (in->texinfo); + + // CalcSurfaceExtentsFPM (out); // FPM doesn't exist + CalcSurfaceExtents (out); + + // lighting info + + for (i=0 ; istyles[i] = in->styles[i]; + i = LittleLong(in->lightofs); + if (i == -1) + out->samples = NULL; + else + out->samples = loadmodelFPM->lightdata + i; + + // set the drawing flags flag + + if (!Q_strncmp(out->texinfo->texture->name,"sky",3)) // sky + { + out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED); + continue; + } + + if (!Q_strncmp(out->texinfo->texture->name,"*",1)) // turbulent + { + out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED); + for (i=0 ; i<2 ; i++) + { + out->extents[i] = 16384; + out->texturemins[i] = -8192; + } + continue; + } + } +} +#endif + +/* +================= +Mod_SetParent +================= +*/ +// Yoda +#pragma DISABLE_OPTIMIZATION +void Mod_SetParent (mnode_t *node, mnode_t *parent) +{ + node->parent = parent; + if (node->contents < 0) + return; + Mod_SetParent (node->children[0], node); + Mod_SetParent (node->children[1], node); +} + +#ifdef USEFPM +void Mod_SetParentFPM (mnode_FPM_t *node, mnode_FPM_t *parent) +{ + node->parent = parent; + if (node->contents < 0) + return; + Mod_SetParentFPM (node->children[0], node); + Mod_SetParentFPM (node->children[1], node); +} +#endif +// Yoda +#pragma ENABLE_OPTIMIZATION +/* +================= +Mod_LoadNodes +================= +*/ +void Mod_LoadNodes (lump_t *l) +{ + int i, j, count, p; + dnode_t *in; + mnode_t *out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->nodes = out; + loadmodel->numnodes = count; + + for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + p = LittleLong(in->planenum); + out->plane = loadmodel->planes + p; + + out->firstsurface = LittleShort (in->firstface); + out->numsurfaces = LittleShort (in->numfaces); + + for (j=0 ; j<2 ; j++) + { + p = LittleShort (in->children[j]); + if (p >= 0) + out->children[j] = loadmodel->nodes + p; + else + out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p)); + } + } + + Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs +} + +#ifdef USEFPM +void Mod_LoadNodesFPM (lump_t *l) +{ + int i, j, count, p; + dnode_t *in; + mnode_FPM_t *out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodelFPM->nodes = out; + loadmodelFPM->numnodes = count; + + for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + p = LittleLong(in->planenum); + out->plane = loadmodelFPM->planes + p; + + out->firstsurface = LittleShort (in->firstface); + out->numsurfaces = LittleShort (in->numfaces); + + for (j=0 ; j<2 ; j++) + { + p = LittleShort (in->children[j]); + if (p >= 0) + out->children[j] = loadmodelFPM->nodes + p; + else + out->children[j] = (mnode_FPM_t *)(loadmodelFPM->leafs + (-1 - p)); + } + } + + Mod_SetParentFPM (loadmodelFPM->nodes, NULL); // sets nodes and leafs +} +#endif + +/* +================= +Mod_LoadLeafs +================= +*/ +void Mod_LoadLeafs (lump_t *l) +{ + dleaf_t *in; + mleaf_t *out; + int i, j, count, p; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->leafs = out; + loadmodel->numleafs = count; + + for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + p = LittleLong(in->contents); + out->contents = p; + + out->firstmarksurface = loadmodel->marksurfaces + + LittleShort(in->firstmarksurface); + out->nummarksurfaces = LittleShort(in->nummarksurfaces); + + p = LittleLong(in->visofs); + if (p == -1) + out->compressed_vis = NULL; + else + out->compressed_vis = loadmodel->visdata + p; + out->efrags = NULL; + + for (j=0 ; j<4 ; j++) + out->ambient_sound_level[j] = in->ambient_level[j]; + } +} + +#ifdef USEFPM +void Mod_LoadLeafsFPM (lump_t *l) +{ + dleaf_t *in; + mleaf_FPM_t *out; + int i, j, count, p; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodelFPM->leafs = out; + loadmodelFPM->numleafs = count; + + for ( i=0 ; iminmaxs[j] = LittleShort (in->mins[j]); + out->minmaxs[3+j] = LittleShort (in->maxs[j]); + } + + p = LittleLong(in->contents); + out->contents = p; + + out->firstmarksurface = loadmodelFPM->marksurfaces + + LittleShort(in->firstmarksurface); + out->nummarksurfaces = LittleShort(in->nummarksurfaces); + + p = LittleLong(in->visofs); + if (p == -1) + out->compressed_vis = NULL; + else + out->compressed_vis = loadmodelFPM->visdata + p; + out->efrags = NULL; + + for (j=0 ; j<4 ; j++) + out->ambient_sound_level[j] = in->ambient_level[j]; + } +} +#endif +/* +================= +Mod_LoadClipnodes +================= +*/ +void Mod_LoadClipnodes (lump_t *l) +{ + dclipnode_t *in, *out; + int i, count; + hull_t *hull; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->clipnodes = out; + loadmodel->numclipnodes = count; + + hull = &loadmodel->hulls[1]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -16; + hull->clip_mins[1] = -16; + hull->clip_mins[2] = -24; + hull->clip_maxs[0] = 16; + hull->clip_maxs[1] = 16; + hull->clip_maxs[2] = 32; + + hull = &loadmodel->hulls[2]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + hull->clip_mins[0] = -32; + hull->clip_mins[1] = -32; + hull->clip_mins[2] = -24; + hull->clip_maxs[0] = 32; + hull->clip_maxs[1] = 32; + hull->clip_maxs[2] = 64; + + for (i=0 ; iplanenum = LittleLong(in->planenum); + out->children[0] = LittleShort(in->children[0]); + out->children[1] = LittleShort(in->children[1]); + } +} + +#ifdef USEFPM +void Mod_LoadClipnodesFPM (lump_t *l) +{ + dclipnode_t *in, *out; + int i, count; + hull_FPM_t *hull; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodelFPM->clipnodes = out; + loadmodelFPM->numclipnodes = count; + + hull = &loadmodelFPM->hulls[1]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodelFPM->planes; + hull->clip_mins[0] = -16; + hull->clip_mins[1] = -16; + hull->clip_mins[2] = -24; + hull->clip_maxs[0] = 16; + hull->clip_maxs[1] = 16; + hull->clip_maxs[2] = 32; + + hull = &loadmodelFPM->hulls[2]; + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodelFPM->planes; + hull->clip_mins[0] = -32; + hull->clip_mins[1] = -32; + hull->clip_mins[2] = -24; + hull->clip_maxs[0] = 32; + hull->clip_maxs[1] = 32; + hull->clip_maxs[2] = 64; + + for (i=0 ; iplanenum = LittleLong(in->planenum); + out->children[0] = LittleShort(in->children[0]); + out->children[1] = LittleShort(in->children[1]); + } +} +#endif + +/* +================= +Mod_MakeHull0 + +Deplicate the drawing hull structure as a clipping hull +================= +*/ +void Mod_MakeHull0 (void) +{ + mnode_t *in, *child; + dclipnode_t *out; + int i, j, count; + hull_t *hull; + + hull = &loadmodel->hulls[0]; + + in = loadmodel->nodes; + count = loadmodel->numnodes; + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodel->planes; + + for (i=0 ; iplanenum = in->plane - loadmodel->planes; + for (j=0 ; j<2 ; j++) + { + child = in->children[j]; + if (child->contents < 0) + out->children[j] = child->contents; + else + out->children[j] = child - loadmodel->nodes; + } + } +} + +#ifdef USEFPM +void Mod_MakeHull0FPM (void) +{ + mnode_FPM_t *in, *child; + dclipnode_t *out; + int i, j, count; + hull_FPM_t *hull; + + hull = &loadmodelFPM->hulls[0]; + + in = loadmodelFPM->nodes; + count = loadmodelFPM->numnodes; + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + hull->clipnodes = out; + hull->firstclipnode = 0; + hull->lastclipnode = count-1; + hull->planes = loadmodelFPM->planes; + + for (i=0 ; iplanenum = in->plane - loadmodelFPM->planes; + for (j=0 ; j<2 ; j++) + { + child = in->children[j]; + if (child->contents < 0) + out->children[j] = child->contents; + else + out->children[j] = child - loadmodelFPM->nodes; + } + } +} +#endif + +/* +================= +Mod_LoadMarksurfaces +================= +*/ +void Mod_LoadMarksurfaces (lump_t *l) +{ + int i, j, count; + short *in; + msurface_t **out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->marksurfaces = out; + loadmodel->nummarksurfaces = count; + + for ( i=0 ; i= loadmodel->numsurfaces) + Sys_Error ("Mod_ParseMarksurfaces: bad surface number"); + out[i] = loadmodel->surfaces + j; + } +} + +#ifdef USEFPM +void Mod_LoadMarksurfacesFPM (lump_t *l) +{ + int i, j, count; + short *in; + msurface_FPM_t **out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodelFPM->marksurfaces = out; + loadmodelFPM->nummarksurfaces = count; + + for ( i=0 ; i= loadmodelFPM->numsurfaces) + Sys_Error ("Mod_ParseMarksurfaces: bad surface number"); + out[i] = loadmodelFPM->surfaces + j; + } +} +#endif + +/* +================= +Mod_LoadSurfedges +================= +*/ +void Mod_LoadSurfedges (lump_t *l) +{ + int i, count; + int *in, *out; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodel->surfedges = out; + loadmodel->numsurfedges = count; + + for ( i=0 ; ifileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*sizeof(*out), loadname); + + loadmodelFPM->surfedges = out; + loadmodelFPM->numsurfedges = count; + + for ( i=0 ; ifileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*2*sizeof(*out), loadname); + + loadmodel->planes = out; + loadmodel->numplanes = count; + + for ( i=0 ; inormal[j] = LittleFloat (in->normal[j]); + if (out->normal[j] < 0) + bits |= 1<dist = LittleFloat (in->dist); + out->type = LittleLong (in->type); + out->signbits = bits; + } +} + +#ifdef USEFPM +void Mod_LoadPlanesFPM (lump_t *l) +{ + int i, j; + mplane_FPM_t *out; + dplane_t *in; + int count; + int bits; + + in = (void *)(mod_base + l->fileofs); + if (l->filelen % sizeof(*in)) + Sys_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); + count = l->filelen / sizeof(*in); + out = Hunk_AllocName ( count*2*sizeof(*out), loadname); + + loadmodelFPM->planes = out; + loadmodelFPM->numplanes = count; + + for ( i=0 ; inormal[j] = FPM_FROMFLOAT(LittleFloat (in->normal[j])); + if (out->normal[j] < 0) + bits |= 1<dist = FPM_FROMFLOAT(LittleFloat (in->dist)); + out->type = LittleLong (in->type); + out->signbits = bits; + } +} +#endif + +/* +================= +RadiusFromBounds +================= +*/ +float RadiusFromBounds (vec3_t mins, vec3_t maxs) +{ + int i; + vec3_t corner; + + for (i=0 ; i<3 ; i++) + { + corner[i] = (float)(fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i])); + } + + return Length (corner); +} + +#ifdef USEFPM +fixedpoint_t RadiusFromBoundsFPM (vec3_FPM_t mins, vec3_FPM_t maxs) +{ + int i; + vec3_FPM_t corner; + + for (i=0 ; i<3 ; i++) + { + corner[i] = (FPM_ABS(mins[i]) > FPM_ABS(maxs[i]) ? FPM_ABS(mins[i]) : FPM_ABS(maxs[i])); + } + + return LengthFPM (corner); +} +#endif + +/* +================= +Mod_LoadBrushModel +================= +*/ +void Mod_LoadBrushModel (model_t *mod, void *buffer) +{ + int i, j; + dheader_t *header; + dmodel_t *bm; + + loadmodel->type = mod_brush; + + header = (dheader_t *)buffer; + + i = LittleLong (header->version); + if (i != BSPVERSION) { + Con_Printf("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION); + mod->numvertexes = -1; + return; + } + +// swap all the lumps + mod_base = (byte *)header; + + for (i=0 ; ilumps[LUMP_VERTEXES]); + Mod_LoadEdges (&header->lumps[LUMP_EDGES]); + Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]); + Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]); + Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]); + Mod_LoadPlanes (&header->lumps[LUMP_PLANES]); + Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]); + Mod_LoadFaces (&header->lumps[LUMP_FACES]); + Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]); + Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]); + Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]); + Mod_LoadNodes (&header->lumps[LUMP_NODES]); + Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]); + Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]); + Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]); + + Mod_MakeHull0 (); + + mod->numframes = 2; // regular and alternate animation + mod->flags = 0; + +// +// set up the submodels (FIXME: this is confusing) +// + for (i=0 ; inumsubmodels ; i++) + { + bm = &mod->submodels[i]; + + mod->hulls[0].firstclipnode = bm->headnode[0]; + for (j=1 ; jhulls[j].firstclipnode = bm->headnode[j]; + mod->hulls[j].lastclipnode = mod->numclipnodes-1; + } + + mod->firstmodelsurface = bm->firstface; + mod->nummodelsurfaces = bm->numfaces; + + VectorCopy (bm->maxs, mod->maxs); + VectorCopy (bm->mins, mod->mins); + mod->radius = RadiusFromBounds (mod->mins, mod->maxs); + + mod->numleafs = bm->visleafs; + + if (i < mod->numsubmodels-1) + { // duplicate the basic information + char name[10]; + + sprintf (name, "*%i", i+1); + loadmodel = Mod_FindName (name); + *loadmodel = *mod; + strcpy (loadmodel->name, name); + mod = loadmodel; + } + } +} + +#ifdef USEFPM +void Mod_LoadBrushModelFPM (model_FPM_t *mod, void *buffer) +{ + int i, j; + dheader_t *header; + dmodel_FPM_t *bm; + + loadmodelFPM->type = mod_brush; + + header = (dheader_t *)buffer; + + i = LittleLong (header->version); + if (i != BSPVERSION) + Sys_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION); + +// swap all the lumps + mod_base = (byte *)header; + + for (i=0 ; ilumps[LUMP_VERTEXES]); // FPM doesn't exist + Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]); + Mod_LoadEdgesFPM (&header->lumps[LUMP_EDGES]); + Mod_LoadSurfedgesFPM (&header->lumps[LUMP_SURFEDGES]); + Mod_LoadTexturesFPM (&header->lumps[LUMP_TEXTURES]); + Mod_LoadLightingFPM (&header->lumps[LUMP_LIGHTING]); + Mod_LoadPlanesFPM (&header->lumps[LUMP_PLANES]); + Mod_LoadTexinfoFPM (&header->lumps[LUMP_TEXINFO]); + Mod_LoadFacesFPM (&header->lumps[LUMP_FACES]); + Mod_LoadMarksurfacesFPM (&header->lumps[LUMP_MARKSURFACES]); + Mod_LoadVisibilityFPM (&header->lumps[LUMP_VISIBILITY]); + Mod_LoadLeafsFPM (&header->lumps[LUMP_LEAFS]); + Mod_LoadNodesFPM (&header->lumps[LUMP_NODES]); + Mod_LoadClipnodesFPM (&header->lumps[LUMP_CLIPNODES]); + Mod_LoadEntitiesFPM (&header->lumps[LUMP_ENTITIES]); + Mod_LoadSubmodelsFPM (&header->lumps[LUMP_MODELS]); + + Mod_MakeHull0FPM (); + + mod->numframes = 2; // regular and alternate animation + mod->flags = 0; + +// +// set up the submodels (FIXME: this is confusing) +// + for (i=0 ; inumsubmodels ; i++) + { + bm = &mod->submodels[i]; + + mod->hulls[0].firstclipnode = bm->headnode[0]; + for (j=1 ; jhulls[j].firstclipnode = bm->headnode[j]; + mod->hulls[j].lastclipnode = mod->numclipnodes-1; + } + + mod->firstmodelsurface = bm->firstface; + mod->nummodelsurfaces = bm->numfaces; + + VectorCopy (bm->maxs, mod->maxs); + VectorCopy (bm->mins, mod->mins); + mod->radius = RadiusFromBoundsFPM (mod->mins, mod->maxs); + + mod->numleafs = bm->visleafs; + + if (i < mod->numsubmodels-1) + { // duplicate the basic information + char name[10]; + + sprintf (name, "*%i", i+1); + loadmodelFPM = Mod_FindNameFPM (name); + *loadmodelFPM = *mod; + strcpy (loadmodelFPM->name, name); + mod = loadmodelFPM; + } + } +} +#endif + +/* +============================================================================== + +ALIAS MODELS + +============================================================================== +*/ + +/* +================= +Mod_LoadAliasFrame +================= +*/ +void * Mod_LoadAliasFrame (void * pin, int *pframeindex, int numv, + trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name) +{ + trivertx_t *pframe, *pinframe; + int i, j; + daliasframe_t *pdaliasframe; + + pdaliasframe = (daliasframe_t *)pin; + + strcpy (name, pdaliasframe->name); + + for (i=0 ; i<3 ; i++) + { + // these are byte values, so we don't have to worry about + // endianness + pbboxmin->v[i] = pdaliasframe->bboxmin.v[i]; + pbboxmax->v[i] = pdaliasframe->bboxmax.v[i]; + } + + pinframe = (trivertx_t *)(pdaliasframe + 1); + pframe = Hunk_AllocName (numv * sizeof(*pframe), loadname); + + *pframeindex = (byte *)pframe - (byte *)pheader; + + for (j=0 ; jnumframes); + + paliasgroup = Hunk_AllocName (sizeof (maliasgroup_t) + + (numframes - 1) * sizeof (paliasgroup->frames[0]), loadname); + + paliasgroup->numframes = numframes; + + for (i=0 ; i<3 ; i++) + { + // these are byte values, so we don't have to worry about endianness + pbboxmin->v[i] = pingroup->bboxmin.v[i]; + pbboxmax->v[i] = pingroup->bboxmax.v[i]; + } + + *pframeindex = (byte *)paliasgroup - (byte *)pheader; + + pin_intervals = (daliasinterval_t *)(pingroup + 1); + + poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname); + + paliasgroup->intervals = (byte *)poutintervals - (byte *)pheader; + + for (i=0 ; iinterval); + if (*poutintervals <= 0.0) + Sys_Error ("Mod_LoadAliasGroup: interval<=0"); + + poutintervals++; + pin_intervals++; + } + + ptemp = (void *)pin_intervals; + + for (i=0 ; iframes[i].frame, + numv, + &paliasgroup->frames[i].bboxmin, + &paliasgroup->frames[i].bboxmax, + pheader, name); + } + + return ptemp; +} + +#ifdef USEFPM +void * Mod_LoadAliasGroupFPM (void * pin, int *pframeindex, int numv, + trivertx_t *pbboxmin, trivertx_t *pbboxmax, aliashdr_t *pheader, char *name) +{ + daliasgroup_t *pingroup; + maliasgroup_t *paliasgroup; + int i, numframes; + daliasinterval_t *pin_intervals; + fixedpoint_t *poutintervals; + void *ptemp; + + pingroup = (daliasgroup_t *)pin; + + numframes = LittleLong (pingroup->numframes); + + paliasgroup = Hunk_AllocName (sizeof (maliasgroup_t) + + (numframes - 1) * sizeof (paliasgroup->frames[0]), loadname); + + paliasgroup->numframes = numframes; + + for (i=0 ; i<3 ; i++) + { + // these are byte values, so we don't have to worry about endianness + pbboxmin->v[i] = pingroup->bboxmin.v[i]; + pbboxmax->v[i] = pingroup->bboxmax.v[i]; + } + + *pframeindex = (byte *)paliasgroup - (byte *)pheader; + + pin_intervals = (daliasinterval_t *)(pingroup + 1); + + poutintervals = Hunk_AllocName (numframes * sizeof (fixedpoint_t), loadname); + + paliasgroup->intervals = (byte *)poutintervals - (byte *)pheader; + + for (i=0 ; iinterval)); + if (*poutintervals <= 0) + Sys_Error ("Mod_LoadAliasGroup: interval<=0"); + + poutintervals++; + pin_intervals++; + } + + ptemp = (void *)pin_intervals; + + for (i=0 ; iframes[i].frame, + numv, + &paliasgroup->frames[i].bboxmin, + &paliasgroup->frames[i].bboxmax, + pheader, name); + } + + return ptemp; +} +#endif + +/* +================= +Mod_LoadAliasSkin +================= +*/ +void * Mod_LoadAliasSkin (void * pin, int *pskinindex, int skinsize, + aliashdr_t *pheader) +{ + int i; + byte *pskin, *pinskin; + unsigned short *pusskin; + + pskin = Hunk_AllocName (skinsize * r_pixbytes, loadname); + pinskin = (byte *)pin; + *pskinindex = (byte *)pskin - (byte *)pheader; + + if (r_pixbytes == 1) + { + Q_memcpy (pskin, pinskin, skinsize); + } + else if (r_pixbytes == 2) + { + pusskin = (unsigned short *)pskin; + + for (i=0 ; inumskins); + + paliasskingroup = Hunk_AllocName (sizeof (maliasskingroup_t) + + (numskins - 1) * sizeof (paliasskingroup->skindescs[0]), + loadname); + + paliasskingroup->numskins = numskins; + + *pskinindex = (byte *)paliasskingroup - (byte *)pheader; + + pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1); + + poutskinintervals = Hunk_AllocName (numskins * sizeof (float),loadname); + + paliasskingroup->intervals = (byte *)poutskinintervals - (byte *)pheader; + + for (i=0 ; iinterval); + if (*poutskinintervals <= 0) + Sys_Error ("Mod_LoadAliasSkinGroup: interval<=0"); + + poutskinintervals++; + pinskinintervals++; + } + + ptemp = (void *)pinskinintervals; + + for (i=0 ; iskindescs[i].skin, skinsize, pheader); + } + + return ptemp; +} + +#ifdef USEFPM +void * Mod_LoadAliasSkinGroupFPM (void * pin, int *pskinindex, int skinsize, + aliashdr_t *pheader) +{ + daliasskingroup_t *pinskingroup; + maliasskingroup_t *paliasskingroup; + int i, numskins; + daliasskininterval_t *pinskinintervals; + fixedpoint_t *poutskinintervals; + void *ptemp; + + pinskingroup = (daliasskingroup_t *)pin; + + numskins = LittleLong (pinskingroup->numskins); + + paliasskingroup = Hunk_AllocName (sizeof (maliasskingroup_t) + + (numskins - 1) * sizeof (paliasskingroup->skindescs[0]), + loadname); + + paliasskingroup->numskins = numskins; + + *pskinindex = (byte *)paliasskingroup - (byte *)pheader; + + pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1); + + poutskinintervals = Hunk_AllocName (numskins * sizeof (fixedpoint_t),loadname); + + paliasskingroup->intervals = (byte *)poutskinintervals - (byte *)pheader; + + for (i=0 ; iinterval)); + if (*poutskinintervals <= 0) + Sys_Error ("Mod_LoadAliasSkinGroup: interval<=0"); + + poutskinintervals++; + pinskinintervals++; + } + + ptemp = (void *)pinskinintervals; + + for (i=0 ; iskindescs[i].skin, skinsize, pheader); + } + + return ptemp; +} +#endif + +/* +================= +Mod_LoadAliasModel +================= +*/ +void Mod_LoadAliasModel (model_t *mod, void *buffer) +{ + int i; + mdl_t *pmodel, *pinmodel; + stvert_t *pstverts, *pinstverts; + aliashdr_t *pheader; + mtriangle_t *ptri; + dtriangle_t *pintriangles; + int version, numframes, numskins; + int size; + daliasframetype_t *pframetype; + daliasskintype_t *pskintype; + maliasskindesc_t *pskindesc; + int skinsize; + int start, end, total; + + start = Hunk_LowMark (); + + pinmodel = (mdl_t *)buffer; + + version = LittleLong (pinmodel->version); + if (version != ALIAS_VERSION) + Sys_Error ("%s has wrong version number (%i should be %i)", + mod->name, version, ALIAS_VERSION); + +// +// allocate space for a working header, plus all the data except the frames, +// skin and group info +// + size = sizeof (aliashdr_t) + (LittleLong (pinmodel->numframes) - 1) * + sizeof (pheader->frames[0]) + + sizeof (mdl_t) + + LittleLong (pinmodel->numverts) * sizeof (stvert_t) + + LittleLong (pinmodel->numtris) * sizeof (mtriangle_t); + + pheader = Hunk_AllocName (size, loadname); + pmodel = (mdl_t *) ((byte *)&pheader[1] + + (LittleLong (pinmodel->numframes) - 1) * + sizeof (pheader->frames[0])); + +// mod->cache.data = pheader; + mod->flags = LittleLong (pinmodel->flags); + +// +// endian-adjust and copy the data, starting with the alias model header +// + pmodel->boundingradius = LittleFloat (pinmodel->boundingradius); + pmodel->numskins = LittleLong (pinmodel->numskins); + pmodel->skinwidth = LittleLong (pinmodel->skinwidth); + pmodel->skinheight = LittleLong (pinmodel->skinheight); + + if (pmodel->skinheight > MAX_LBM_HEIGHT) + Sys_Error ("model %s has a skin taller than %d", mod->name, + MAX_LBM_HEIGHT); + + pmodel->numverts = LittleLong (pinmodel->numverts); + + if (pmodel->numverts <= 0) + Sys_Error ("model %s has no vertices", mod->name); + + if (pmodel->numverts > MAXALIASVERTS) + Sys_Error ("model %s has too many vertices", mod->name); + + pmodel->numtris = LittleLong (pinmodel->numtris); + + if (pmodel->numtris <= 0) + Sys_Error ("model %s has no triangles", mod->name); + + pmodel->numframes = LittleLong (pinmodel->numframes); + pmodel->size = (float)(LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO); + mod->synctype = LittleLong (pinmodel->synctype); + mod->numframes = pmodel->numframes; + + for (i=0 ; i<3 ; i++) + { + pmodel->scale[i] = LittleFloat (pinmodel->scale[i]); + pmodel->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]); + pmodel->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]); + } + + numskins = pmodel->numskins; + numframes = pmodel->numframes; + + if (pmodel->skinwidth & 0x03) + Sys_Error ("Mod_LoadAliasModel: skinwidth not multiple of 4"); + + pheader->model = (byte *)pmodel - (byte *)pheader; + +// +// load the skins +// + skinsize = pmodel->skinheight * pmodel->skinwidth; + + if (numskins < 1) + Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins); + + pskintype = (daliasskintype_t *)&pinmodel[1]; + + pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t), + loadname); + + pheader->skindesc = (byte *)pskindesc - (byte *)pheader; + + for (i=0 ; itype); + pskindesc[i].type = skintype; + + if (skintype == ALIAS_SKIN_SINGLE) + { + pskintype = (daliasskintype_t *) + Mod_LoadAliasSkin (pskintype + 1, + &pskindesc[i].skin, + skinsize, pheader); + } + else + { + pskintype = (daliasskintype_t *) + Mod_LoadAliasSkinGroup (pskintype + 1, + &pskindesc[i].skin, + skinsize, pheader); + } + } + +// +// set base s and t vertices +// + pstverts = (stvert_t *)&pmodel[1]; + pinstverts = (stvert_t *)pskintype; + + pheader->stverts = (byte *)pstverts - (byte *)pheader; + + for (i=0 ; inumverts ; i++) + { + pstverts[i].onseam = LittleLong (pinstverts[i].onseam); + // put s and t in 16.16 format + pstverts[i].s = LittleLong (pinstverts[i].s) << 16; + pstverts[i].t = LittleLong (pinstverts[i].t) << 16; + } + +// +// set up the triangles +// + ptri = (mtriangle_t *)&pstverts[pmodel->numverts]; + pintriangles = (dtriangle_t *)&pinstverts[pmodel->numverts]; + + pheader->triangles = (byte *)ptri - (byte *)pheader; + + for (i=0 ; inumtris ; i++) + { + int j; + + ptri[i].facesfront = LittleLong (pintriangles[i].facesfront); + + for (j=0 ; j<3 ; j++) + { + ptri[i].vertindex[j] = + LittleLong (pintriangles[i].vertindex[j]); + } + } + +// +// load the frames +// + if (numframes < 1) + Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes); + + pframetype = (daliasframetype_t *)&pintriangles[pmodel->numtris]; + + for (i=0 ; itype); + pheader->frames[i].type = frametype; + + if (frametype == ALIAS_SINGLE) + { + pframetype = (daliasframetype_t *) + Mod_LoadAliasFrame (pframetype + 1, + &pheader->frames[i].frame, + pmodel->numverts, + &pheader->frames[i].bboxmin, + &pheader->frames[i].bboxmax, + pheader, pheader->frames[i].name); + } + else + { + pframetype = (daliasframetype_t *) + Mod_LoadAliasGroup (pframetype + 1, + &pheader->frames[i].frame, + pmodel->numverts, + &pheader->frames[i].bboxmin, + &pheader->frames[i].bboxmax, + pheader, pheader->frames[i].name); + } + } + + mod->type = mod_alias; + +// FIXME: do this right + mod->mins[0] = mod->mins[1] = mod->mins[2] = -16; + mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 16; + +// +// move the complete, relocatable alias model to the cache +// + end = Hunk_LowMark (); + total = end - start; + + Cache_Alloc (&mod->cache, total, loadname); + if (!mod->cache.data) + return; + Q_memcpy (mod->cache.data, pheader, total); + + Hunk_FreeToLowMark (start); +} + +#ifdef USEFPM +void Mod_LoadAliasModelFPM (model_FPM_t *mod, void *buffer) +{ + int i; + mdl_t *pinmodel; + mdl_FPM_t *pmodel; + stvert_t *pstverts, *pinstverts; + aliashdr_t *pheader; + mtriangle_t *ptri; + dtriangle_t *pintriangles; + int version, numframes, numskins; + int size; + daliasframetype_t *pframetype; + daliasskintype_t *pskintype; + maliasskindesc_t *pskindesc; + int skinsize; + int start, end, total; + + start = Hunk_LowMark (); + + pinmodel = (mdl_t *)buffer; + + version = LittleLong (pinmodel->version); + if (version != ALIAS_VERSION) + Sys_Error ("%s has wrong version number (%i should be %i)", + mod->name, version, ALIAS_VERSION); + +// +// allocate space for a working header, plus all the data except the frames, +// skin and group info +// + size = sizeof (aliashdr_t) + (LittleLong (pinmodel->numframes) - 1) * + sizeof (pheader->frames[0]) + + sizeof (mdl_FPM_t) + + LittleLong (pinmodel->numverts) * sizeof (stvert_t) + + LittleLong (pinmodel->numtris) * sizeof (mtriangle_t); + + pheader = Hunk_AllocName (size, loadname); + pmodel = (mdl_FPM_t *) ((byte *)&pheader[1] + + (LittleLong (pinmodel->numframes) - 1) * + sizeof (pheader->frames[0])); + +// mod->cache.data = pheader; + mod->flags = LittleLong (pinmodel->flags); + +// +// endian-adjust and copy the data, starting with the alias model header +// + pmodel->boundingradius = FPM_FROMFLOAT(LittleFloat (pinmodel->boundingradius)); + pmodel->numskins = LittleLong (pinmodel->numskins); + pmodel->skinwidth = LittleLong (pinmodel->skinwidth); + pmodel->skinheight = LittleLong (pinmodel->skinheight); + + if (pmodel->skinheight > MAX_LBM_HEIGHT) + Sys_Error ("model %s has a skin taller than %d", mod->name, + MAX_LBM_HEIGHT); + + pmodel->numverts = LittleLong (pinmodel->numverts); + + if (pmodel->numverts <= 0) + Sys_Error ("model %s has no vertices", mod->name); + + if (pmodel->numverts > MAXALIASVERTS) + Sys_Error ("model %s has too many vertices", mod->name); + + pmodel->numtris = LittleLong (pinmodel->numtris); + + if (pmodel->numtris <= 0) + Sys_Error ("model %s has no triangles", mod->name); + + pmodel->numframes = LittleLong (pinmodel->numframes); + pmodel->size = FPM_MUL(FPM_FROMFLOAT(LittleFloat (pinmodel->size)), FPM_FROMFLOAT(ALIAS_BASE_SIZE_RATIO)); + mod->synctype = LittleLong (pinmodel->synctype); + mod->numframes = pmodel->numframes; + + for (i=0 ; i<3 ; i++) + { + pmodel->scale[i] = FPM_FROMFLOAT(LittleFloat (pinmodel->scale[i])); + pmodel->scale_origin[i] = FPM_FROMFLOAT(LittleFloat (pinmodel->scale_origin[i])); + pmodel->eyeposition[i] = FPM_FROMFLOAT(LittleFloat (pinmodel->eyeposition[i])); + } + + numskins = pmodel->numskins; + numframes = pmodel->numframes; + + if (pmodel->skinwidth & 0x03) + Sys_Error ("Mod_LoadAliasModel: skinwidth not multiple of 4"); + + pheader->model = (byte *)pmodel - (byte *)pheader; + +// +// load the skins +// + skinsize = pmodel->skinheight * pmodel->skinwidth; + + if (numskins < 1) + Sys_Error ("Mod_LoadAliasModel: Invalid # of skins: %d\n", numskins); + + pskintype = (daliasskintype_t *)&pinmodel[1]; + + pskindesc = Hunk_AllocName (numskins * sizeof (maliasskindesc_t), + loadname); + + pheader->skindesc = (byte *)pskindesc - (byte *)pheader; + + for (i=0 ; itype); + pskindesc[i].type = skintype; + + if (skintype == ALIAS_SKIN_SINGLE) + { + pskintype = (daliasskintype_t *) + Mod_LoadAliasSkin (pskintype + 1, + &pskindesc[i].skin, + skinsize, pheader); + } + else + { + pskintype = (daliasskintype_t *) + Mod_LoadAliasSkinGroupFPM (pskintype + 1, + &pskindesc[i].skin, + skinsize, pheader); + } + } + +// +// set base s and t vertices +// + pstverts = (stvert_t *)&pmodel[1]; + pinstverts = (stvert_t *)pskintype; + + pheader->stverts = (byte *)pstverts - (byte *)pheader; + + for (i=0 ; inumverts ; i++) + { + pstverts[i].onseam = LittleLong (pinstverts[i].onseam); + // put s and t in 16.16 format + pstverts[i].s = LittleLong (pinstverts[i].s) << 16; + pstverts[i].t = LittleLong (pinstverts[i].t) << 16; + } + +// +// set up the triangles +// + ptri = (mtriangle_t *)&pstverts[pmodel->numverts]; + pintriangles = (dtriangle_t *)&pinstverts[pmodel->numverts]; + + pheader->triangles = (byte *)ptri - (byte *)pheader; + + + for (i=0 ; inumtris ; i++) + { + int j; + + ptri[i].facesfront = LittleLong (pintriangles[i].facesfront); + + for (j=0 ; j<3 ; j++) + ptri[i].vertindex[j] = + LittleLong (pintriangles[i].vertindex[j]); + } + +// +// load the frames +// + if (numframes < 1) + Sys_Error ("Mod_LoadAliasModel: Invalid # of frames: %d\n", numframes); + + pframetype = (daliasframetype_t *)&pintriangles[pmodel->numtris]; + + for (i=0 ; itype); + pheader->frames[i].type = frametype; + + if (frametype == ALIAS_SINGLE) + { + pframetype = (daliasframetype_t *) + Mod_LoadAliasFrame (pframetype + 1, + &pheader->frames[i].frame, + pmodel->numverts, + &pheader->frames[i].bboxmin, + &pheader->frames[i].bboxmax, + pheader, pheader->frames[i].name); + } + else + { + pframetype = (daliasframetype_t *) + Mod_LoadAliasGroupFPM (pframetype + 1, + &pheader->frames[i].frame, + pmodel->numverts, + &pheader->frames[i].bboxmin, + &pheader->frames[i].bboxmax, + pheader, pheader->frames[i].name); + } + } + + mod->type = mod_alias; + +// FIXME: do this right + mod->mins[0] = mod->mins[1] = mod->mins[2] = -16; + mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 16; + +// +// move the complete, relocatable alias model to the cache +// + end = Hunk_LowMark (); + total = end - start; + + Cache_Alloc (&mod->cache, total, loadname); + if (!mod->cache.data) + return; + Q_memcpy (mod->cache.data, pheader, total); + + Hunk_FreeToLowMark (start); +} +#endif + +//============================================================================= + +/* +================= +Mod_LoadSpriteFrame +================= +*/ +void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe) +{ + dspriteframe_t *pinframe; + mspriteframe_t *pspriteframe; + int i, width, height, size, origin[2]; + unsigned short *ppixout; + byte *ppixin; + + pinframe = (dspriteframe_t *)pin; + + width = LittleLong (pinframe->width); + height = LittleLong (pinframe->height); + size = width * height; + + pspriteframe = Hunk_AllocName (sizeof (mspriteframe_t) + size*r_pixbytes, + loadname); + + Q_memset (pspriteframe, 0, sizeof (mspriteframe_t) + size); + *ppframe = pspriteframe; + + pspriteframe->width = width; + pspriteframe->height = height; + origin[0] = LittleLong (pinframe->origin[0]); + origin[1] = LittleLong (pinframe->origin[1]); + + pspriteframe->up = (float)origin[1]; + pspriteframe->down = (float)origin[1] - height; + pspriteframe->left = (float)origin[0]; + pspriteframe->right = (float)width + origin[0]; + + if (r_pixbytes == 1) + { + Q_memcpy (&pspriteframe->pixels[0], (byte *)(pinframe + 1), size); + } + else if (r_pixbytes == 2) + { + ppixin = (byte *)(pinframe + 1); + ppixout = (unsigned short *)&pspriteframe->pixels[0]; + + for (i=0 ; iwidth); + height = LittleLong (pinframe->height); + size = width * height; + + pspriteframe = Hunk_AllocName (sizeof (mspriteframe_FPM_t) + size*r_pixbytes, + loadname); + + Q_memset (pspriteframe, 0, sizeof (mspriteframe_FPM_t) + size); + *ppframe = pspriteframe; + + pspriteframe->width = width; + pspriteframe->height = height; + origin[0] = LittleLong (pinframe->origin[0]); + origin[1] = LittleLong (pinframe->origin[1]); + + pspriteframe->up = FPM_FROMLONG(origin[1]); + pspriteframe->down = FPM_FROMLONG(origin[1] - height); + pspriteframe->left = FPM_FROMLONG(origin[0]); + pspriteframe->right = FPM_FROMLONG(width + origin[0]); + + if (r_pixbytes == 1) + { + Q_memcpy (&pspriteframe->pixels[0], (byte *)(pinframe + 1), size); + } + else if (r_pixbytes == 2) + { + ppixin = (byte *)(pinframe + 1); + ppixout = (unsigned short *)&pspriteframe->pixels[0]; + + for (i=0 ; inumframes); + + pspritegroup = Hunk_AllocName (sizeof (mspritegroup_t) + + (numframes - 1) * sizeof (pspritegroup->frames[0]), loadname); + + pspritegroup->numframes = numframes; + + *ppframe = (mspriteframe_t *)pspritegroup; + + pin_intervals = (dspriteinterval_t *)(pingroup + 1); + + poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname); + + pspritegroup->intervals = poutintervals; + + for (i=0 ; iinterval); + if (*poutintervals <= 0.0) + Sys_Error ("Mod_LoadSpriteGroup: interval<=0"); + + poutintervals++; + pin_intervals++; + } + + ptemp = (void *)pin_intervals; + + for (i=0 ; iframes[i]); + } + + return ptemp; +} + +#ifdef USEFPM +void * Mod_LoadSpriteGroupFPM (void * pin, mspriteframe_FPM_t **ppframe) +{ + dspritegroup_t *pingroup; + mspritegroup_FPM_t *pspritegroup; + int i, numframes; + dspriteinterval_t *pin_intervals; + fixedpoint_t *poutintervals; + void *ptemp; + + pingroup = (dspritegroup_t *)pin; + + numframes = LittleLong (pingroup->numframes); + + pspritegroup = Hunk_AllocName (sizeof (mspritegroup_FPM_t) + + (numframes - 1) * sizeof (pspritegroup->frames[0]), loadname); + + pspritegroup->numframes = numframes; + + *ppframe = (mspriteframe_FPM_t *)pspritegroup; + + pin_intervals = (dspriteinterval_t *)(pingroup + 1); + + poutintervals = Hunk_AllocName (numframes * sizeof (fixedpoint_t), loadname); + + pspritegroup->intervals = poutintervals; + + for (i=0 ; iinterval)); + if (*poutintervals <= 0) + Sys_Error ("Mod_LoadSpriteGroup: interval<=0"); + + poutintervals++; + pin_intervals++; + } + + ptemp = (void *)pin_intervals; + + for (i=0 ; iframes[i]); + } + + return ptemp; +} +#endif + +/* +================= +Mod_LoadSpriteModel +================= +*/ +void Mod_LoadSpriteModel (model_t *mod, void *buffer) +{ + int i; + int version; + dsprite_t *pin; + msprite_t *psprite; + int numframes; + int size; + dspriteframetype_t *pframetype; + + pin = (dsprite_t *)buffer; + + version = LittleLong (pin->version); + if (version != SPRITE_VERSION) + Sys_Error ("%s has wrong version number " + "(%i should be %i)", mod->name, version, SPRITE_VERSION); + + numframes = LittleLong (pin->numframes); + + size = sizeof (msprite_t) + (numframes - 1) * sizeof (psprite->frames); + + psprite = Hunk_AllocName (size, loadname); + + mod->cache.data = psprite; + + psprite->type = LittleLong (pin->type); + psprite->maxwidth = LittleLong (pin->width); + psprite->maxheight = LittleLong (pin->height); + psprite->beamlength = LittleFloat (pin->beamlength); + mod->synctype = LittleLong (pin->synctype); + psprite->numframes = numframes; + + mod->mins[0] = mod->mins[1] = -((float)psprite->maxwidth)/2; + mod->maxs[0] = mod->maxs[1] = ((float)psprite->maxwidth)/2; + mod->mins[2] = -((float)psprite->maxheight)/2; + mod->maxs[2] = ((float)psprite->maxheight)/2; + +// +// load the frames +// + if (numframes < 1) + Sys_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes); + + mod->numframes = numframes; + mod->flags = 0; + + pframetype = (dspriteframetype_t *)(pin + 1); + + for (i=0 ; itype); + psprite->frames[i].type = frametype; + + if (frametype == SPR_SINGLE) + { + pframetype = (dspriteframetype_t *) + Mod_LoadSpriteFrame (pframetype + 1, + &psprite->frames[i].frameptr); + } + else + { + pframetype = (dspriteframetype_t *) + Mod_LoadSpriteGroup (pframetype + 1, + &psprite->frames[i].frameptr); + } + } + + mod->type = mod_sprite; +} + +#ifdef USEFPM +void Mod_LoadSpriteModelFPM (model_FPM_t *mod, void *buffer) +{ + int i; + int version; + dsprite_t *pin; + msprite_FPM_t *psprite; + int numframes; + int size; + dspriteframetype_t *pframetype; + + pin = (dsprite_t *)buffer; + + version = LittleLong (pin->version); + if (version != SPRITE_VERSION) + Sys_Error ("%s has wrong version number " + "(%i should be %i)", mod->name, version, SPRITE_VERSION); + + numframes = LittleLong (pin->numframes); + + size = sizeof (msprite_FPM_t) + (numframes - 1) * sizeof (psprite->frames); + + psprite = Hunk_AllocName (size, loadname); + + mod->cache.data = psprite; + + psprite->type = LittleLong (pin->type); + psprite->maxwidth = LittleLong (pin->width); + psprite->maxheight = LittleLong (pin->height); + psprite->beamlength = FPM_FROMFLOAT(LittleFloat (pin->beamlength)); + mod->synctype = LittleLong (pin->synctype); + psprite->numframes = numframes; + + mod->mins[0] = mod->mins[1] = -FPM_DIV(FPM_FROMLONG(psprite->maxwidth),FPM_FROMLONG(2)); + mod->maxs[0] = mod->maxs[1] = FPM_DIV(FPM_FROMLONG(psprite->maxwidth),FPM_FROMLONG(2)); + mod->mins[2] = -FPM_DIV(FPM_FROMLONG(psprite->maxheight),FPM_FROMLONG(2)); + mod->maxs[2] = FPM_DIV(FPM_FROMLONG(psprite->maxheight),FPM_FROMLONG(2)); + +// +// load the frames +// + if (numframes < 1) + Sys_Error ("Mod_LoadSpriteModel: Invalid # of frames: %d\n", numframes); + + mod->numframes = numframes; + mod->flags = 0; + + pframetype = (dspriteframetype_t *)(pin + 1); + + for (i=0 ; itype); + psprite->frames[i].type = frametype; + + if (frametype == SPR_SINGLE) + { + pframetype = (dspriteframetype_t *) + Mod_LoadSpriteFrameFPM (pframetype + 1, + &psprite->frames[i].frameptr); + } + else + { + pframetype = (dspriteframetype_t *) + Mod_LoadSpriteGroupFPM (pframetype + 1, + &psprite->frames[i].frameptr); + } + } + + mod->type = mod_sprite; +} +#endif +//============================================================================= + +/* +================ +Mod_Print +================ +*/ +void Mod_Print (void) +{ + int i; + model_t *mod; + + Con_Printf ("Cached models:\n"); + for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++) + { + Con_Printf ("%8p : %s",mod->cache.data, mod->name); + if (mod->needload & NL_UNREFERENCED) + Con_Printf (" (!R)"); + if (mod->needload & NL_NEEDS_LOADED) + Con_Printf (" (!P)"); + Con_Printf ("\n"); + } +} + +#ifdef USEFPM +void Mod_PrintFPM (void) +{ + int i; + model_FPM_t *mod; + + Con_Printf ("Cached models:\n"); + for (i=0, mod=mod_knownFPM ; i < mod_numknown ; i++, mod++) + { + Con_Printf ("%8p : %s",mod->cache.data, mod->name); + if (mod->needload & NL_UNREFERENCED) + Con_Printf (" (!R)"); + if (mod->needload & NL_NEEDS_LOADED) + Con_Printf (" (!P)"); + Con_Printf ("\n"); + } +} +#endif diff --git a/project/jni/application/quake/source/model.h b/project/jni/application/quake/source/model.h new file mode 100644 index 000000000..7c2bdd62b --- /dev/null +++ b/project/jni/application/quake/source/model.h @@ -0,0 +1,605 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifndef __MODEL__ +#define __MODEL__ + +#include "modelgen.h" +#include "spritegn.h" + +/* + +d*_t structures are on-disk representations +m*_t structures are in-memory + +*/ + +/* +============================================================================== + +BRUSH MODELS + +============================================================================== +*/ + + +// +// in memory representation +// +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct +{ + vec3_t position; +} mvertex_t; + +typedef struct +{ + int position[3]; +} mvertex_fxp_t; +/* +typedef struct +{ + vec3_FPM_t position; +} mvertex_FPM_t; +*/ +#define SIDE_FRONT 0 +#define SIDE_BACK 1 +#define SIDE_ON 2 + + +// plane_t structure +// !!! if this is changed, it must be changed in asm_i386.h too !!! +typedef struct mplane_s +{ + vec3_t normal; + float dist; + byte type; // for texture axis selection and fast side tests + byte signbits; // signx + signy<<1 + signz<<1 + byte pad[2]; +} mplane_t; + +//Dan East: Fixed Point Math addition +/* +typedef struct mplane_FPM_s +{ + vec3_FPM_t normal; + fixedpoint_t dist; + byte type; // for texture axis selection and fast side tests + byte signbits; // signx + signy<<1 + signz<<1 + byte pad[2]; +} mplane_FPM_t; +*/ + +typedef struct texture_s +{ + char name[16]; + unsigned width, height; + int anim_total; // total tenths in sequence ( 0 = no) + int anim_min, anim_max; // time for this frame min <=time< max + struct texture_s *anim_next; // in the animation sequence + struct texture_s *alternate_anims; // bmodels in frmae 1 use these + unsigned offsets[MIPLEVELS]; // four mip maps stored +} texture_t; + + +#define SURF_PLANEBACK 2 +#define SURF_DRAWSKY 4 +#define SURF_DRAWSPRITE 8 +#define SURF_DRAWTURB 0x10 +#define SURF_DRAWTILED 0x20 +#define SURF_DRAWBACKGROUND 0x40 + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct +{ + unsigned short v[2]; + unsigned int cachededgeoffset; +} medge_t; + +typedef struct +{ +#ifndef USE_PQ_OPT3 + float vecs[2][4]; + float mipadjust; +#else + int vecs_fxp[2][4]; + int mipadjust_fxp; +#endif + texture_t *texture; + int flags; +} mtexinfo_t; +/* +typedef struct +{ + fixedpoint_t vecs[2][4]; + fixedpoint_t mipadjust; + texture_t *texture; + int flags; +} mtexinfo_FPM_t; +*/ +typedef struct msurface_s +{ + int visframe; // should be drawn when node is crossed + + int dlightframe; + int dlightbits; + + mplane_t *plane; + int flags; + + int firstedge; // look up in model->surfedges[], negative numbers + int numedges; // are backwards edges + +// surface generation data + struct surfcache_s *cachespots[MIPLEVELS]; + + short texturemins[2]; + short extents[2]; + + mtexinfo_t *texinfo; + +// lighting info + byte styles[MAXLIGHTMAPS]; + byte *samples; // [numstyles*surfsize] +} msurface_t; +/* +typedef struct msurface_FPM_s +{ + int visframe; // should be drawn when node is crossed + + int dlightframe; + int dlightbits; + + mplane_FPM_t *plane; + int flags; + + int firstedge; // look up in model->surfedges[], negative numbers + int numedges; // are backwards edges + +// surface generation data + struct surfcache_FPM_s *cachespots[MIPLEVELS]; + + short texturemins[2]; + short extents[2]; + + mtexinfo_FPM_t *texinfo; + +// lighting info + byte styles[MAXLIGHTMAPS]; + byte *samples; // [numstyles*surfsize] +} msurface_FPM_t; +*/ +typedef struct mnode_s +{ +// common with leaf + int contents; // 0, to differentiate from leafs + int visframe; // node needs to be traversed if current + + short minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + +// node specific + mplane_t *plane; + struct mnode_s *children[2]; + + unsigned short firstsurface; + unsigned short numsurfaces; +} mnode_t; +/* +typedef struct mnode_FPM_s +{ +// common with leaf + int contents; // 0, to differentiate from leafs + int visframe; // node needs to be traversed if current + + short minmaxs[6]; // for bounding box culling + + struct mnode_FPM_s *parent; + +// node specific + mplane_FPM_t *plane; + struct mnode_FPM_s *children[2]; + + unsigned short firstsurface; + unsigned short numsurfaces; +} mnode_FPM_t; +*/ + + +typedef struct mleaf_s +{ +// common with node + int contents; // wil be a negative contents number + int visframe; // node needs to be traversed if current + + short minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + +// leaf specific + byte *compressed_vis; + efrag_t *efrags; + + msurface_t **firstmarksurface; + int nummarksurfaces; + int key; // BSP sequence number for leaf's contents + byte ambient_sound_level[NUM_AMBIENTS]; +} mleaf_t; +/* +typedef struct mleaf_FPM_s +{ +// common with node + int contents; // wil be a negative contents number + int visframe; // node needs to be traversed if current + + short minmaxs[6]; // for bounding box culling + + struct mnode_s *parent; + +// leaf specific + byte *compressed_vis; + efrag_FPM_t *efrags; + + msurface_FPM_t **firstmarksurface; + int nummarksurfaces; + int key; // BSP sequence number for leaf's contents + byte ambient_sound_level[NUM_AMBIENTS]; +} mleaf_FPM_t; +*/ +// !!! if this is changed, it must be changed in asm_i386.h too !!! +typedef struct +{ + dclipnode_t *clipnodes; + mplane_t *planes; + int firstclipnode; + int lastclipnode; + vec3_t clip_mins; + vec3_t clip_maxs; +} hull_t; +/* +typedef struct +{ + dclipnode_t *clipnodes; + mplane_FPM_t *planes; + int firstclipnode; + int lastclipnode; + vec3_FPM_t clip_mins; + vec3_FPM_t clip_maxs; +} hull_FPM_t; +*/ +/* +============================================================================== + +SPRITE MODELS + +============================================================================== +*/ + + +// FIXME: shorten these? +typedef struct mspriteframe_s +{ + int width; + int height; + void *pcachespot; // remove? + float up, down, left, right; + byte pixels[4]; +} mspriteframe_t; +/* +typedef struct mspriteframe_FPM_s +{ + int width; + int height; + void *pcachespot; // remove? + fixedpoint_t up, down, left, right; + byte pixels[4]; +} mspriteframe_FPM_t; +*/ +typedef struct +{ + int numframes; + float *intervals; + mspriteframe_t *frames[1]; +} mspritegroup_t; +/* +typedef struct +{ + int numframes; + fixedpoint_t *intervals; + mspriteframe_FPM_t *frames[1]; +} mspritegroup_FPM_t; +*/ +typedef struct +{ + spriteframetype_t type; + mspriteframe_t *frameptr; +} mspriteframedesc_t; +/* +typedef struct +{ + spriteframetype_t type; + mspriteframe_FPM_t *frameptr; +} mspriteframedesc_FPM_t; +*/ +typedef struct +{ + int type; + int maxwidth; + int maxheight; + int numframes; + float beamlength; // remove? + void *cachespot; // remove? + mspriteframedesc_t frames[1]; +} msprite_t; +/* +typedef struct +{ + int type; + int maxwidth; + int maxheight; + int numframes; + fixedpoint_t beamlength; // remove? + void *cachespot; // remove? + mspriteframedesc_FPM_t frames[1]; +} msprite_FPM_t; +*/ + +/* +============================================================================== + +ALIAS MODELS + +Alias models are position independent, so the cache manager can move them. +============================================================================== +*/ + +typedef struct +{ + aliasframetype_t type; + trivertx_t bboxmin; + trivertx_t bboxmax; + int frame; + char name[16]; +} maliasframedesc_t; + +typedef struct +{ + aliasskintype_t type; + void *pcachespot; + int skin; +} maliasskindesc_t; + +typedef struct +{ + trivertx_t bboxmin; + trivertx_t bboxmax; + int frame; +} maliasgroupframedesc_t; + +typedef struct +{ + int numframes; + int intervals; + maliasgroupframedesc_t frames[1]; +} maliasgroup_t; + +typedef struct +{ + int numskins; + int intervals; + maliasskindesc_t skindescs[1]; +} maliasskingroup_t; + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct mtriangle_s { + int facesfront; + int vertindex[3]; +} mtriangle_t; + +typedef struct { + int model; + int stverts; + int skindesc; + int triangles; + maliasframedesc_t frames[1]; +} aliashdr_t; + +//=================================================================== + +// +// Whole model +// + +typedef enum {mod_brush, mod_sprite, mod_alias} modtype_t; + +#define EF_ROCKET 1 // leave a trail +#define EF_GRENADE 2 // leave a trail +#define EF_GIB 4 // leave a trail +#define EF_ROTATE 8 // rotate (bonus items) +#define EF_TRACER 16 // green split trail +#define EF_ZOMGIB 32 // small blood trail +#define EF_TRACER2 64 // orange split trail + rotate +#define EF_TRACER3 128 // purple trail + +typedef struct model_s +{ + char name[MAX_QPATH]; + qboolean needload; // bmodels and sprites don't cache normally + + modtype_t type; + int numframes; + synctype_t synctype; + + int flags; + +// +// volume occupied by the model +// + vec3_t mins, maxs; + float radius; + +// +// brush model +// + int firstmodelsurface, nummodelsurfaces; + + int numsubmodels; + dmodel_t *submodels; + + int numplanes; + mplane_t *planes; + + int numleafs; // number of visible leafs, not counting 0 + mleaf_t *leafs; + + int numvertexes; + mvertex_t *vertexes; + +#ifdef USE_PQ_OPT2 + mvertex_fxp_t *vertexes_fxp; +#endif + + int numedges; + medge_t *edges; + + int numnodes; + mnode_t *nodes; + + int numtexinfo; + mtexinfo_t *texinfo; + + int numsurfaces; + msurface_t *surfaces; + + int numsurfedges; + int *surfedges; + + int numclipnodes; + dclipnode_t *clipnodes; + + int nummarksurfaces; + msurface_t **marksurfaces; + + hull_t hulls[MAX_MAP_HULLS]; + + int numtextures; + texture_t **textures; + + byte *visdata; + byte *lightdata; + char *entities; + +// +// additional model data +// + cache_user_t cache; // only access through Mod_Extradata + +} model_t; +/* +typedef struct model_FPM_s +{ + char name[MAX_QPATH]; + qboolean needload; // bmodels and sprites don't cache normally + + modtype_t type; + int numframes; + synctype_t synctype; + + int flags; + +// +// volume occupied by the model +// + vec3_FPM_t mins, maxs; + fixedpoint_t radius; + +// +// brush model +// + int firstmodelsurface, nummodelsurfaces; + + int numsubmodels; + dmodel_FPM_t *submodels; + + int numplanes; + mplane_FPM_t *planes; + + int numleafs; // number of visible leafs, not counting 0 + mleaf_FPM_t *leafs; + + int numvertexes; + mvertex_FPM_t *vertexes; + + int numedges; + medge_t *edges; + + int numnodes; + mnode_FPM_t *nodes; + + int numtexinfo; + mtexinfo_FPM_t *texinfo; + + int numsurfaces; + msurface_FPM_t *surfaces; + + int numsurfedges; + int *surfedges; + + int numclipnodes; + dclipnode_t *clipnodes; + + int nummarksurfaces; + msurface_FPM_t **marksurfaces; + + hull_FPM_t hulls[MAX_MAP_HULLS]; + + int numtextures; + texture_t **textures; + + byte *visdata; + byte *lightdata; + char *entities; + +// +// additional model data +// + cache_user_t cache; // only access through Mod_Extradata + +} model_FPM_t; +*/ +//============================================================================ + +void Mod_Init (void); +void Mod_ClearAll (void); +//void Mod_ClearAllFPM (void); +model_t *Mod_ForName (char *name, qboolean crash); +//model_FPM_t *Mod_ForNameFPM (char *name, qboolean crash); +void *Mod_Extradata (model_t *mod); // handles caching +//void *Mod_ExtradataFPM (model_FPM_t *mod); // handles caching +void Mod_TouchModel (char *name); +void Mod_TouchModelFPM (char *name); + +mleaf_t *Mod_PointInLeaf (float *p, model_t *model); +//mleaf_FPM_t *Mod_PointInLeafFPM (fixedpoint_t *p, model_FPM_t *model); +byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model); +//byte *Mod_LeafPVSFPM (mleaf_FPM_t *leaf, model_FPM_t *model); + +#endif // __MODEL__ diff --git a/project/jni/application/quake/source/modelgen.h b/project/jni/application/quake/source/modelgen.h new file mode 100644 index 000000000..c3a61367a --- /dev/null +++ b/project/jni/application/quake/source/modelgen.h @@ -0,0 +1,157 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// modelgen.h: header file for model generation program +// + +// ********************************************************* +// * This file must be identical in the modelgen directory * +// * and in the Quake directory, because it's used to * +// * pass data from one to the other via model files. * +// ********************************************************* + +#ifdef INCLUDELIBS + +#include +#include +#include +#include + +//#include "cmdlib.h" +//#include "scriplib.h" +//#include "trilib.h" +//#include "lbmlib.h" +//#include "mathlib.h" + +#endif + +#define ALIAS_VERSION 6 + +#define ALIAS_ONSEAM 0x0020 + +// must match definition in spritegn.h +#ifndef SYNCTYPE_T +#define SYNCTYPE_T +typedef enum {ST_SYNC=0, ST_RAND } synctype_t; +#endif + +typedef enum { ALIAS_SINGLE=0, ALIAS_GROUP } aliasframetype_t; + +typedef enum { ALIAS_SKIN_SINGLE=0, ALIAS_SKIN_GROUP } aliasskintype_t; + +typedef struct { + int ident; + int version; + vec3_t scale; + vec3_t scale_origin; + float boundingradius; + vec3_t eyeposition; + int numskins; + int skinwidth; + int skinheight; + int numverts; + int numtris; + int numframes; + synctype_t synctype; + int flags; + float size; +} mdl_t; + +//Dan East: +typedef struct { + int ident; + int version; + vec3_FPM_t scale; + vec3_FPM_t scale_origin; + fixedpoint_t boundingradius; + vec3_FPM_t eyeposition; + int numskins; + int skinwidth; + int skinheight; + int numverts; + int numtris; + int numframes; + synctype_t synctype; + int flags; + fixedpoint_t size; +} mdl_FPM_t; + +// TODO: could be shorts + +typedef struct { + int onseam; + int s; + int t; +} stvert_t; + +typedef struct dtriangle_s { + int facesfront; + int vertindex[3]; +} dtriangle_t; + +#define DT_FACES_FRONT 0x0010 + +// This mirrors trivert_t in trilib.h, is present so Quake knows how to +// load this data + +typedef struct { + byte v[3]; + byte lightnormalindex; +} trivertx_t; + +typedef struct { + trivertx_t bboxmin; // lightnormal isn't used + trivertx_t bboxmax; // lightnormal isn't used + char name[16]; // frame name from grabbing +} daliasframe_t; + +typedef struct { + int numframes; + trivertx_t bboxmin; // lightnormal isn't used + trivertx_t bboxmax; // lightnormal isn't used +} daliasgroup_t; + +typedef struct { + int numskins; +} daliasskingroup_t; + +typedef struct { + float interval; +} daliasinterval_t; +/* +typedef struct { + fixedpoint_t interval; +} daliasinterval_FPM_t; +*/ +typedef struct { + float interval; +} daliasskininterval_t; + +typedef struct { + aliasframetype_t type; +} daliasframetype_t; + +typedef struct { + aliasskintype_t type; +} daliasskintype_t; + +#define IDPOLYHEADER (('O'<<24)+('P'<<16)+('D'<<8)+'I') + // little-endian "IDPO" + diff --git a/project/jni/application/quake/source/mplane.h b/project/jni/application/quake/source/mplane.h new file mode 100644 index 000000000..508ab102f --- /dev/null +++ b/project/jni/application/quake/source/mplane.h @@ -0,0 +1,21 @@ +// plane_t structure +// !!! if this is changed, it must be changed in asm_i386.h too !!! +typedef struct mplane_s +{ + vec3_t normal; + float dist; + byte type; // for texture axis selection and fast side tests + byte signbits; // signx + signy<<1 + signz<<1 + byte pad[2]; +} mplane_t; + +//Dan East: Fixed Point Math addition +typedef struct mplane_FPM_s +{ + vec3_FPM_t normal; + fixedpoint_t dist; + byte type; // for texture axis selection and fast side tests + byte signbits; // signx + signy<<1 + signz<<1 + byte pad[2]; +} mplane_FPM_t; + diff --git a/project/jni/application/quake/source/net.h b/project/jni/application/quake/source/net.h new file mode 100644 index 000000000..c84cef44c --- /dev/null +++ b/project/jni/application/quake/source/net.h @@ -0,0 +1,337 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net.h -- quake's interface to the networking layer + +struct qsockaddr +{ + short sa_family; + unsigned char sa_data[14]; +}; + + +#define NET_NAMELEN 64 + +#define NET_MAXMESSAGE 8192 +#define NET_HEADERSIZE (2 * sizeof(unsigned int)) +#define NET_DATAGRAMSIZE (MAX_DATAGRAM + NET_HEADERSIZE) + +// NetHeader flags +#define NETFLAG_LENGTH_MASK 0x0000ffff +#define NETFLAG_DATA 0x00010000 +#define NETFLAG_ACK 0x00020000 +#define NETFLAG_NAK 0x00040000 +#define NETFLAG_EOM 0x00080000 +#define NETFLAG_UNRELIABLE 0x00100000 +#define NETFLAG_CTL 0x80000000 + + +#define NET_PROTOCOL_VERSION 3 + +// This is the network info/connection protocol. It is used to find Quake +// servers, get info about them, and connect to them. Once connected, the +// Quake game protocol (documented elsewhere) is used. +// +// +// General notes: +// game_name is currently always "QUAKE", but is there so this same protocol +// can be used for future games as well; can you say Quake2? +// +// CCREQ_CONNECT +// string game_name "QUAKE" +// byte net_protocol_version NET_PROTOCOL_VERSION +// +// CCREQ_SERVER_INFO +// string game_name "QUAKE" +// byte net_protocol_version NET_PROTOCOL_VERSION +// +// CCREQ_PLAYER_INFO +// byte player_number +// +// CCREQ_RULE_INFO +// string rule +// +// +// +// CCREP_ACCEPT +// long port +// +// CCREP_REJECT +// string reason +// +// CCREP_SERVER_INFO +// string server_address +// string host_name +// string level_name +// byte current_players +// byte max_players +// byte protocol_version NET_PROTOCOL_VERSION +// +// CCREP_PLAYER_INFO +// byte player_number +// string name +// long colors +// long frags +// long connect_time +// string address +// +// CCREP_RULE_INFO +// string rule +// string value + +// note: +// There are two address forms used above. The short form is just a +// port number. The address that goes along with the port is defined as +// "whatever address you receive this reponse from". This lets us use +// the host OS to solve the problem of multiple host addresses (possibly +// with no routing between them); the host will use the right address +// when we reply to the inbound connection request. The long from is +// a full address and port in a string. It is used for returning the +// address of a server that is not running locally. + +#define CCREQ_CONNECT 0x01 +#define CCREQ_SERVER_INFO 0x02 +#define CCREQ_PLAYER_INFO 0x03 +#define CCREQ_RULE_INFO 0x04 + +#define CCREP_ACCEPT 0x81 +#define CCREP_REJECT 0x82 +#define CCREP_SERVER_INFO 0x83 +#define CCREP_PLAYER_INFO 0x84 +#define CCREP_RULE_INFO 0x85 + +typedef struct qsocket_s +{ + struct qsocket_s *next; + double connecttime; + double lastMessageTime; + double lastSendTime; + + qboolean disconnected; + qboolean canSend; + qboolean sendNext; + + int driver; + int landriver; + int socket; + void *driverdata; + + unsigned int ackSequence; + unsigned int sendSequence; + unsigned int unreliableSendSequence; + int sendMessageLength; + byte sendMessage [NET_MAXMESSAGE]; + + unsigned int receiveSequence; + unsigned int unreliableReceiveSequence; + int receiveMessageLength; + byte receiveMessage [NET_MAXMESSAGE]; + + struct qsockaddr addr; + char address[NET_NAMELEN]; + +} qsocket_t; + +extern qsocket_t *net_activeSockets; +extern qsocket_t *net_freeSockets; +extern int net_numsockets; + +typedef struct +{ + char *name; + qboolean initialized; + int controlSock; + int (*Init) (void); + void (*Shutdown) (void); + void (*Listen) (qboolean state); + int (*OpenSocket) (int port); + int (*CloseSocket) (int socket); + int (*Connect) (int socket, struct qsockaddr *addr); + int (*CheckNewConnections) (void); + int (*Read) (int socket, byte *buf, int len, struct qsockaddr *addr); + int (*Write) (int socket, byte *buf, int len, struct qsockaddr *addr); + int (*Broadcast) (int socket, byte *buf, int len); + char * (*AddrToString) (struct qsockaddr *addr); + int (*StringToAddr) (char *string, struct qsockaddr *addr); + int (*GetSocketAddr) (int socket, struct qsockaddr *addr); + int (*GetNameFromAddr) (struct qsockaddr *addr, char *name); + int (*GetAddrFromName) (char *name, struct qsockaddr *addr); + int (*AddrCompare) (struct qsockaddr *addr1, struct qsockaddr *addr2); + int (*GetSocketPort) (struct qsockaddr *addr); + int (*SetSocketPort) (struct qsockaddr *addr, int port); +} net_landriver_t; + +#define MAX_NET_DRIVERS 8 +extern int net_numlandrivers; +extern net_landriver_t net_landrivers[MAX_NET_DRIVERS]; + +typedef struct +{ + char *name; + qboolean initialized; + int (*Init) (void); + void (*Listen) (qboolean state); + void (*SearchForHosts) (qboolean xmit); + qsocket_t *(*Connect) (char *host); + qsocket_t *(*CheckNewConnections) (void); + int (*QGetMessage) (qsocket_t *sock); + int (*QSendMessage) (qsocket_t *sock, sizebuf_t *data); + int (*SendUnreliableMessage) (qsocket_t *sock, sizebuf_t *data); + qboolean (*CanSendMessage) (qsocket_t *sock); + qboolean (*CanSendUnreliableMessage) (qsocket_t *sock); + void (*Close) (qsocket_t *sock); + void (*Shutdown) (void); + int controlSock; +} net_driver_t; + +extern int net_numdrivers; +extern net_driver_t net_drivers[MAX_NET_DRIVERS]; + +extern int DEFAULTnet_hostport; +extern int net_hostport; + +extern int net_driverlevel; +extern cvar_t hostname; +extern char playername[]; +extern int playercolor; + +extern int messagesSent; +extern int messagesReceived; +extern int unreliableMessagesSent; +extern int unreliableMessagesReceived; + +qsocket_t *NET_NewQSocket (void); +void NET_FreeQSocket(qsocket_t *); +double SetNetTime(void); + + +#define HOSTCACHESIZE 8 + +typedef struct +{ + char name[16]; + char map[16]; + char cname[32]; + int users; + int maxusers; + int driver; + int ldriver; + struct qsockaddr addr; +} hostcache_t; + +extern int hostCacheCount; +extern hostcache_t hostcache[HOSTCACHESIZE]; + +#if !defined(_WIN32 ) && !defined (__linux__) && !defined (__sun__) +#ifndef htonl +extern unsigned long htonl (unsigned long hostlong); +#endif +#ifndef htons +extern unsigned short htons (unsigned short hostshort); +#endif +#ifndef ntohl +extern unsigned long ntohl (unsigned long netlong); +#endif +#ifndef ntohs +extern unsigned short ntohs (unsigned short netshort); +#endif +#endif + +#ifdef IDGODS +qboolean IsID(struct qsockaddr *addr); +#endif + +//============================================================================ +// +// public network functions +// +//============================================================================ + +extern double net_time; +extern sizebuf_t net_message; +extern int net_activeconnections; + +void NET_Init (void); +void NET_Shutdown (void); + +struct qsocket_s *NET_CheckNewConnections (void); +// returns a new connection number if there is one pending, else -1 + +struct qsocket_s *NET_Connect (char *host); +// called by client to connect to a host. Returns -1 if not able to + +qboolean NET_CanSendMessage (qsocket_t *sock); +// Returns true or false if the given qsocket can currently accept a +// message to be transmitted. + +int NET_GetMessage (struct qsocket_s *sock); +// returns data in net_message sizebuf +// returns 0 if no data is waiting +// returns 1 if a message was received +// returns 2 if an unreliable message was received +// returns -1 if the connection died + +int NET_SendMessage (struct qsocket_s *sock, sizebuf_t *data); +int NET_SendUnreliableMessage (struct qsocket_s *sock, sizebuf_t *data); +// returns 0 if the message connot be delivered reliably, but the connection +// is still considered valid +// returns 1 if the message was sent properly +// returns -1 if the connection died + +int NET_SendToAll(sizebuf_t *data, int blocktime); +// This is a reliable *blocking* send to all attached clients. + + +void NET_Close (struct qsocket_s *sock); +// if a dead connection is returned by a get or send function, this function +// should be called when it is convenient + +// Server calls when a client is kicked off for a game related misbehavior +// like an illegal protocal conversation. Client calls when disconnecting +// from a server. +// A netcon_t number will not be reused until this function is called for it + +void NET_Poll(void); + + +typedef struct _PollProcedure +{ + struct _PollProcedure *next; + double nextTime; + void (*procedure)(); + void *arg; +} PollProcedure; + +void SchedulePollProcedure(PollProcedure *pp, double timeOffset); + +extern qboolean serialAvailable; +extern qboolean ipxAvailable; +extern qboolean tcpipAvailable; +extern char my_ipx_address[NET_NAMELEN]; +extern char my_tcpip_address[NET_NAMELEN]; +extern void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem); +extern void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem); +extern void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup); +extern void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup); + +extern qboolean slistInProgress; +extern qboolean slistSilent; +extern qboolean slistLocal; + +void NET_Slist_f (void); diff --git a/project/jni/application/quake/source/net_bsd.c b/project/jni/application/quake/source/net_bsd.c new file mode 100644 index 000000000..79d62f859 --- /dev/null +++ b/project/jni/application/quake/source/net_bsd.c @@ -0,0 +1,93 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include "quakedef.h" + +#include "net_loop.h" +#include "net_dgrm.h" + +net_driver_t net_drivers[MAX_NET_DRIVERS] = +{ + { + "Loopback", + false, + Loop_Init, + Loop_Listen, + Loop_SearchForHosts, + Loop_Connect, + Loop_CheckNewConnections, + Loop_GetMessage, + Loop_SendMessage, + Loop_SendUnreliableMessage, + Loop_CanSendMessage, + Loop_CanSendUnreliableMessage, + Loop_Close, + Loop_Shutdown + } + , + { + "Datagram", + false, + Datagram_Init, + Datagram_Listen, + Datagram_SearchForHosts, + Datagram_Connect, + Datagram_CheckNewConnections, + Datagram_GetMessage, + Datagram_SendMessage, + Datagram_SendUnreliableMessage, + Datagram_CanSendMessage, + Datagram_CanSendUnreliableMessage, + Datagram_Close, + Datagram_Shutdown + } +}; + +int net_numdrivers = 2; + +#include "net_udp.h" + +net_landriver_t net_landrivers[MAX_NET_DRIVERS] = +{ + { + "UDP", + false, + 0, + UDP_Init, + UDP_Shutdown, + UDP_Listen, + UDP_OpenSocket, + UDP_CloseSocket, + UDP_Connect, + UDP_CheckNewConnections, + UDP_Read, + UDP_Write, + UDP_Broadcast, + UDP_AddrToString, + UDP_StringToAddr, + UDP_GetSocketAddr, + UDP_GetNameFromAddr, + UDP_GetAddrFromName, + UDP_AddrCompare, + UDP_GetSocketPort, + UDP_SetSocketPort + } +}; + +int net_numlandrivers = 1; diff --git a/project/jni/application/quake/source/net_dgrm.c b/project/jni/application/quake/source/net_dgrm.c new file mode 100644 index 000000000..91e3c9f86 --- /dev/null +++ b/project/jni/application/quake/source/net_dgrm.c @@ -0,0 +1,1400 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_dgrm.c + +// This is enables a simple IP banning mechanism +#define BAN_TEST + +#ifdef BAN_TEST +#if defined(_WIN32) +#include +#elif defined (NeXT) +#include +#include +#else +#define AF_INET 2 /* internet */ +struct in_addr +{ + union + { + struct { unsigned char s_b1,s_b2,s_b3,s_b4; } S_un_b; + struct { unsigned short s_w1,s_w2; } S_un_w; + unsigned long S_addr; + } S_un; +}; +#define s_addr S_un.S_addr /* can be used for most tcp & ip code */ +struct sockaddr_in +{ + short sin_family; + unsigned short sin_port; + struct in_addr sin_addr; + char sin_zero[8]; +}; +char *inet_ntoa(struct in_addr in); +unsigned long inet_addr(const char *cp); +#endif +#endif // BAN_TEST + +#include "quakedef.h" +#include "net_dgrm.h" + +// these two macros are to make the code more readable +#define sfunc net_landrivers[sock->landriver] +#define dfunc net_landrivers[net_landriverlevel] + +static int net_landriverlevel; + +/* statistic counters */ +int packetsSent = 0; +int packetsReSent = 0; +int packetsReceived = 0; +int receivedDuplicateCount = 0; +int shortPacketCount = 0; +int droppedDatagrams; + +static int myDriverLevel; + +struct +{ + unsigned int length; + unsigned int sequence; + byte data[MAX_DATAGRAM]; +} packetBuffer; + +extern int m_return_state; +extern int m_state; +extern qboolean m_return_onerror; +extern char m_return_reason[32]; + + +#ifdef DEBUG +char *StrAddr (struct qsockaddr *addr) +{ + static char buf[34]; + byte *p = (byte *)addr; + int n; + + for (n = 0; n < 16; n++) + sprintf (buf + n * 2, "%02x", *p++); + return buf; +} +#endif + + +#ifdef BAN_TEST +unsigned long banAddr = 0x00000000; +unsigned long banMask = 0xffffffff; + +void NET_Ban_f (void) +{ + char addrStr [32]; + char maskStr [32]; + void (*print) (char *fmt, ...); + + if (cmd_source == src_command) + { + if (!sv.active) + { + Cmd_ForwardToServer (); + return; + } + print = Con_Printf; + } + else + { + if (pr_global_struct->deathmatch && !host_client->privileged) + return; + print = SV_ClientPrintf; + } + + switch (Cmd_Argc ()) + { + case 1: + if (((struct in_addr *)&banAddr)->s_addr) + { + Q_strcpy(addrStr, inet_ntoa(*(struct in_addr *)&banAddr)); + Q_strcpy(maskStr, inet_ntoa(*(struct in_addr *)&banMask)); + print("Banning %s [%s]\n", addrStr, maskStr); + } + else + print("Banning not active\n"); + break; + + case 2: + if (Q_strcasecmp(Cmd_Argv(1), "off") == 0) + banAddr = 0x00000000; + else + banAddr = inet_addr(Cmd_Argv(1)); + banMask = 0xffffffff; + break; + + case 3: + banAddr = inet_addr(Cmd_Argv(1)); + banMask = inet_addr(Cmd_Argv(2)); + break; + + default: + print("BAN ip_address [mask]\n"); + break; + } +} +#endif + + +int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data) +{ + unsigned int packetLen; + unsigned int dataLen; + unsigned int eom; + +#ifdef DEBUG + if (data->cursize == 0) + Sys_Error("Datagram_SendMessage: zero length message\n"); + + if (data->cursize > NET_MAXMESSAGE) + Sys_Error("Datagram_SendMessage: message too big %u\n", data->cursize); + + if (sock->canSend == false) + Sys_Error("SendMessage: called with canSend == false\n"); +#endif + + Q_memcpy(sock->sendMessage, data->data, data->cursize); + sock->sendMessageLength = data->cursize; + + if (data->cursize <= MAX_DATAGRAM) + { + dataLen = data->cursize; + eom = NETFLAG_EOM; + } + else + { + dataLen = MAX_DATAGRAM; + eom = 0; + } + packetLen = NET_HEADERSIZE + dataLen; + + packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom)); + packetBuffer.sequence = BigLong(sock->sendSequence++); + Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen); + + sock->canSend = false; + + if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1) + return -1; + + sock->lastSendTime = net_time; + packetsSent++; + return 1; +} + + +int SendMessageNext (qsocket_t *sock) +{ + unsigned int packetLen; + unsigned int dataLen; + unsigned int eom; + + if (sock->sendMessageLength <= MAX_DATAGRAM) + { + dataLen = sock->sendMessageLength; + eom = NETFLAG_EOM; + } + else + { + dataLen = MAX_DATAGRAM; + eom = 0; + } + packetLen = NET_HEADERSIZE + dataLen; + + packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom)); + packetBuffer.sequence = BigLong(sock->sendSequence++); + Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen); + + sock->sendNext = false; + + if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1) + return -1; + + sock->lastSendTime = net_time; + packetsSent++; + return 1; +} + + +int ReSendMessage (qsocket_t *sock) +{ + unsigned int packetLen; + unsigned int dataLen; + unsigned int eom; + + if (sock->sendMessageLength <= MAX_DATAGRAM) + { + dataLen = sock->sendMessageLength; + eom = NETFLAG_EOM; + } + else + { + dataLen = MAX_DATAGRAM; + eom = 0; + } + packetLen = NET_HEADERSIZE + dataLen; + + packetBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom)); + packetBuffer.sequence = BigLong(sock->sendSequence - 1); + Q_memcpy (packetBuffer.data, sock->sendMessage, dataLen); + + sock->sendNext = false; + + if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1) + return -1; + + sock->lastSendTime = net_time; + packetsReSent++; + return 1; +} + + +qboolean Datagram_CanSendMessage (qsocket_t *sock) +{ + if (sock->sendNext) + SendMessageNext (sock); + + return sock->canSend; +} + + +qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock) +{ + return true; +} + + +int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data) +{ + int packetLen; + +#ifdef DEBUG + if (data->cursize == 0) + Sys_Error("Datagram_SendUnreliableMessage: zero length message\n"); + + if (data->cursize > MAX_DATAGRAM) + Sys_Error("Datagram_SendUnreliableMessage: message too big %u\n", data->cursize); +#endif + + packetLen = NET_HEADERSIZE + data->cursize; + + packetBuffer.length = BigLong(packetLen | NETFLAG_UNRELIABLE); + packetBuffer.sequence = BigLong(sock->unreliableSendSequence++); + Q_memcpy (packetBuffer.data, data->data, data->cursize); + + if (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1) + return -1; + + packetsSent++; + return 1; +} + + +int Datagram_GetMessage (qsocket_t *sock) +{ + unsigned int length; + unsigned int flags; + int ret = 0; + struct qsockaddr readaddr; + unsigned int sequence; + unsigned int count; + + if (!sock->canSend) + if ((net_time - sock->lastSendTime) > 1.0) + ReSendMessage (sock); + + while(1) + { + length = sfunc.Read (sock->socket, (byte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr); + +// if ((rand() & 255) > 220) +// continue; + + if (length == 0) + break; + + if (length == -1) + { + Con_Printf("Read error\n"); + return -1; + } + + if (sfunc.AddrCompare(&readaddr, &sock->addr) != 0) + { +#ifdef DEBUG + Con_DPrintf("Forged packet received\n"); + Con_DPrintf("Expected: %s\n", StrAddr (&sock->addr)); + Con_DPrintf("Received: %s\n", StrAddr (&readaddr)); +#endif + continue; + } + + if (length < NET_HEADERSIZE) + { + shortPacketCount++; + continue; + } + + length = BigLong(packetBuffer.length); + flags = length & (~NETFLAG_LENGTH_MASK); + length &= NETFLAG_LENGTH_MASK; + + if (flags & NETFLAG_CTL) + continue; + + sequence = BigLong(packetBuffer.sequence); + packetsReceived++; + + if (flags & NETFLAG_UNRELIABLE) + { + if (sequence < sock->unreliableReceiveSequence) + { + Con_DPrintf("Got a stale datagram\n"); + ret = 0; + break; + } + if (sequence != sock->unreliableReceiveSequence) + { + count = sequence - sock->unreliableReceiveSequence; + droppedDatagrams += count; + Con_DPrintf("Dropped %u datagram(s)\n", count); + } + sock->unreliableReceiveSequence = sequence + 1; + + length -= NET_HEADERSIZE; + + SZ_Clear (&net_message); + SZ_Write (&net_message, packetBuffer.data, length); + + ret = 2; + break; + } + + if (flags & NETFLAG_ACK) + { + if (sequence != (sock->sendSequence - 1)) + { + Con_DPrintf("Stale ACK received\n"); + continue; + } + if (sequence == sock->ackSequence) + { + sock->ackSequence++; + if (sock->ackSequence != sock->sendSequence) + Con_DPrintf("ack sequencing error\n"); + } + else + { + Con_DPrintf("Duplicate ACK received\n"); + continue; + } + sock->sendMessageLength -= MAX_DATAGRAM; + if (sock->sendMessageLength > 0) + { + Q_memcpy(sock->sendMessage, sock->sendMessage+MAX_DATAGRAM, sock->sendMessageLength); + sock->sendNext = true; + } + else + { + sock->sendMessageLength = 0; + sock->canSend = true; + } + continue; + } + + if (flags & NETFLAG_DATA) + { + packetBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK); + packetBuffer.sequence = BigLong(sequence); + sfunc.Write (sock->socket, (byte *)&packetBuffer, NET_HEADERSIZE, &readaddr); + + if (sequence != sock->receiveSequence) + { + receivedDuplicateCount++; + continue; + } + sock->receiveSequence++; + + length -= NET_HEADERSIZE; + + if (flags & NETFLAG_EOM) + { + SZ_Clear(&net_message); + SZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength); + SZ_Write(&net_message, packetBuffer.data, length); + sock->receiveMessageLength = 0; + + ret = 1; + break; + } + + Q_memcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length); + sock->receiveMessageLength += length; + continue; + } + } + + if (sock->sendNext) + SendMessageNext (sock); + + return ret; +} + + +void PrintStats(qsocket_t *s) +{ + Con_Printf("canSend = %4u \n", s->canSend); + Con_Printf("sendSeq = %4u ", s->sendSequence); + Con_Printf("recvSeq = %4u \n", s->receiveSequence); + Con_Printf("\n"); +} + +void NET_Stats_f (void) +{ + qsocket_t *s; + + if (Cmd_Argc () == 1) + { + Con_Printf("unreliable messages sent = %i\n", unreliableMessagesSent); + Con_Printf("unreliable messages recv = %i\n", unreliableMessagesReceived); + Con_Printf("reliable messages sent = %i\n", messagesSent); + Con_Printf("reliable messages received = %i\n", messagesReceived); + Con_Printf("packetsSent = %i\n", packetsSent); + Con_Printf("packetsReSent = %i\n", packetsReSent); + Con_Printf("packetsReceived = %i\n", packetsReceived); + Con_Printf("receivedDuplicateCount = %i\n", receivedDuplicateCount); + Con_Printf("shortPacketCount = %i\n", shortPacketCount); + Con_Printf("droppedDatagrams = %i\n", droppedDatagrams); + } + else if (Q_strcmp(Cmd_Argv(1), "*") == 0) + { + for (s = net_activeSockets; s; s = s->next) + PrintStats(s); + for (s = net_freeSockets; s; s = s->next) + PrintStats(s); + } + else + { + for (s = net_activeSockets; s; s = s->next) + if (Q_strcasecmp(Cmd_Argv(1), s->address) == 0) + break; + if (s == NULL) + for (s = net_freeSockets; s; s = s->next) + if (Q_strcasecmp(Cmd_Argv(1), s->address) == 0) + break; + if (s == NULL) + return; + PrintStats(s); + } +} + + +static qboolean testInProgress = false; +static int testPollCount; +static int testDriver; +static int testSocket; + +static void Test_Poll(void); +PollProcedure testPollProcedure = {NULL, 0.0, Test_Poll}; + +static void Test_Poll(void) +{ + struct qsockaddr clientaddr; + int control; + int len; + char name[32]; + char address[64]; + int colors; + int frags; + int connectTime; + byte playerNumber; + + net_landriverlevel = testDriver; + + while (1) + { + len = dfunc.Read (testSocket, net_message.data, net_message.maxsize, &clientaddr); + if (len < sizeof(int)) + break; + + net_message.cursize = len; + + MSG_BeginReading (); + control = BigLong(*((int *)net_message.data)); + MSG_ReadLong(); + if (control == -1) + break; + if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) + break; + if ((control & NETFLAG_LENGTH_MASK) != len) + break; + + if (MSG_ReadByte() != CCREP_PLAYER_INFO) + Sys_Error("Unexpected repsonse to Player Info request\n"); + + playerNumber = MSG_ReadByte(); + Q_strcpy(name, MSG_ReadString()); + colors = MSG_ReadLong(); + frags = MSG_ReadLong(); + connectTime = MSG_ReadLong(); + Q_strcpy(address, MSG_ReadString()); + + Con_Printf("%s\n frags:%3i colors:%u %u time:%u\n %s\n", name, frags, colors >> 4, colors & 0x0f, connectTime / 60, address); + } + + testPollCount--; + if (testPollCount) + { + SchedulePollProcedure(&testPollProcedure, 0.1); + } + else + { + dfunc.CloseSocket(testSocket); + testInProgress = false; + } +} + +static void Test_f (void) +{ + char *host; + int n; + int max = MAX_SCOREBOARD; + struct qsockaddr sendaddr; + + if (testInProgress) + return; + + host = Cmd_Argv (1); + + if (host && hostCacheCount) + { + for (n = 0; n < hostCacheCount; n++) + if (Q_strcasecmp (host, hostcache[n].name) == 0) + { + if (hostcache[n].driver != myDriverLevel) + continue; + net_landriverlevel = hostcache[n].ldriver; + max = hostcache[n].maxusers; + Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr)); + break; + } + if (n < hostCacheCount) + goto JustDoIt; + } + + for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) + { + if (!net_landrivers[net_landriverlevel].initialized) + continue; + + // see if we can resolve the host name + if (dfunc.GetAddrFromName(host, &sendaddr) != -1) + break; + } + if (net_landriverlevel == net_numlandrivers) + return; + +JustDoIt: + testSocket = dfunc.OpenSocket(0); + if (testSocket == -1) + return; + + testInProgress = true; + testPollCount = 20; + testDriver = net_landriverlevel; + + for (n = 0; n < max; n++) + { + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREQ_PLAYER_INFO); + MSG_WriteByte(&net_message, n); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (testSocket, net_message.data, net_message.cursize, &sendaddr); + } + SZ_Clear(&net_message); + SchedulePollProcedure(&testPollProcedure, 0.1); +} + + +static qboolean test2InProgress = false; +static int test2Driver; +static int test2Socket; + +static void Test2_Poll(void); +PollProcedure test2PollProcedure = {NULL, 0.0, Test2_Poll}; + +static void Test2_Poll(void) +{ + struct qsockaddr clientaddr; + int control; + int len; + char name[256]; + char value[256]; + + net_landriverlevel = test2Driver; + name[0] = 0; + + len = dfunc.Read (test2Socket, net_message.data, net_message.maxsize, &clientaddr); + if (len < sizeof(int)) + goto Reschedule; + + net_message.cursize = len; + + MSG_BeginReading (); + control = BigLong(*((int *)net_message.data)); + MSG_ReadLong(); + if (control == -1) + goto Error; + if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) + goto Error; + if ((control & NETFLAG_LENGTH_MASK) != len) + goto Error; + + if (MSG_ReadByte() != CCREP_RULE_INFO) + goto Error; + + Q_strcpy(name, MSG_ReadString()); + if (name[0] == 0) + goto Done; + Q_strcpy(value, MSG_ReadString()); + + Con_Printf("%-16.16s %-16.16s\n", name, value); + + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREQ_RULE_INFO); + MSG_WriteString(&net_message, name); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (test2Socket, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + +Reschedule: + SchedulePollProcedure(&test2PollProcedure, 0.05); + return; + +Error: + Con_Printf("Unexpected repsonse to Rule Info request\n"); +Done: + dfunc.CloseSocket(test2Socket); + test2InProgress = false; + return; +} + +static void Test2_f (void) +{ + char *host; + int n; + struct qsockaddr sendaddr; + + if (test2InProgress) + return; + + host = Cmd_Argv (1); + + if (host && hostCacheCount) + { + for (n = 0; n < hostCacheCount; n++) + if (Q_strcasecmp (host, hostcache[n].name) == 0) + { + if (hostcache[n].driver != myDriverLevel) + continue; + net_landriverlevel = hostcache[n].ldriver; + Q_memcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr)); + break; + } + if (n < hostCacheCount) + goto JustDoIt; + } + + for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) + { + if (!net_landrivers[net_landriverlevel].initialized) + continue; + + // see if we can resolve the host name + if (dfunc.GetAddrFromName(host, &sendaddr) != -1) + break; + } + if (net_landriverlevel == net_numlandrivers) + return; + +JustDoIt: + test2Socket = dfunc.OpenSocket(0); + if (test2Socket == -1) + return; + + test2InProgress = true; + test2Driver = net_landriverlevel; + + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREQ_RULE_INFO); + MSG_WriteString(&net_message, ""); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (test2Socket, net_message.data, net_message.cursize, &sendaddr); + SZ_Clear(&net_message); + SchedulePollProcedure(&test2PollProcedure, 0.05); +} + + +int Datagram_Init (void) +{ + int i; + int csock; + + myDriverLevel = net_driverlevel; + Cmd_AddCommand ("net_stats", NET_Stats_f); + + if (COM_CheckParm("-nolan")) + return -1; + + for (i = 0; i < net_numlandrivers; i++) + { + csock = net_landrivers[i].Init (); + if (csock == -1) + continue; + net_landrivers[i].initialized = true; + net_landrivers[i].controlSock = csock; + } + +#ifdef BAN_TEST + Cmd_AddCommand ("ban", NET_Ban_f); +#endif + Cmd_AddCommand ("test", Test_f); + Cmd_AddCommand ("test2", Test2_f); + + return 0; +} + + +void Datagram_Shutdown (void) +{ + int i; + +// +// shutdown the lan drivers +// + for (i = 0; i < net_numlandrivers; i++) + { + if (net_landrivers[i].initialized) + { + net_landrivers[i].Shutdown (); + net_landrivers[i].initialized = false; + } + } +} + + +void Datagram_Close (qsocket_t *sock) +{ + sfunc.CloseSocket(sock->socket); +} + + +void Datagram_Listen (qboolean state) +{ + int i; + + for (i = 0; i < net_numlandrivers; i++) + if (net_landrivers[i].initialized) + net_landrivers[i].Listen (state); +} + + +static qsocket_t *_Datagram_CheckNewConnections (void) +{ + struct qsockaddr clientaddr; + struct qsockaddr newaddr; + int newsock; + int acceptsock; + qsocket_t *sock; + qsocket_t *s; + int len; + int command; + int control; + int ret; + + acceptsock = dfunc.CheckNewConnections(); + if (acceptsock == -1) + return NULL; + + SZ_Clear(&net_message); + + len = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr); + if (len < sizeof(int)) + return NULL; + net_message.cursize = len; + + MSG_BeginReading (); + control = BigLong(*((int *)net_message.data)); + MSG_ReadLong(); + if (control == -1) + return NULL; + if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) { + for (s = net_activeSockets; s; s = s->next) { + if (s->driver != net_driverlevel) + continue; + + ret = dfunc.AddrCompare(&clientaddr, &s->addr); + if (ret == 1) { + dfunc.Connect(s->socket, &clientaddr); + return NULL; + } + } + } + if ((control & NETFLAG_LENGTH_MASK) != len) + return NULL; + + command = MSG_ReadByte(); + if (command == CCREQ_SERVER_INFO) + { + if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0) + return NULL; + + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_SERVER_INFO); + dfunc.GetSocketAddr(acceptsock, &newaddr); + MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr)); + MSG_WriteString(&net_message, hostname.string); + MSG_WriteString(&net_message, sv.name); + MSG_WriteByte(&net_message, net_activeconnections); + MSG_WriteByte(&net_message, svs.maxclients); + MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + return NULL; + } + + if (command == CCREQ_PLAYER_INFO) + { + int playerNumber; + int activeNumber; + int clientNumber; + client_t *client; + + playerNumber = MSG_ReadByte(); + activeNumber = -1; + for (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++) + { + if (client->active) + { + activeNumber++; + if (activeNumber == playerNumber) + break; + } + } + if (clientNumber == svs.maxclients) + return NULL; + + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_PLAYER_INFO); + MSG_WriteByte(&net_message, playerNumber); + MSG_WriteString(&net_message, client->name); + MSG_WriteLong(&net_message, client->colors); + MSG_WriteLong(&net_message, (int)client->edict->v.frags); + MSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime)); + MSG_WriteString(&net_message, client->netconnection->address); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + + return NULL; + } + + if (command == CCREQ_RULE_INFO) + { + char *prevCvarName; + cvar_t *var; + + // find the search start location + prevCvarName = MSG_ReadString(); + if (*prevCvarName) + { + var = Cvar_FindVar (prevCvarName); + if (!var) + return NULL; + var = var->next; + } + else + var = cvar_vars; + + // search for the next server cvar + while (var) + { + if (var->server) + break; + var = var->next; + } + + // send the response + + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_RULE_INFO); + if (var) + { + MSG_WriteString(&net_message, var->name); + MSG_WriteString(&net_message, var->string); + } + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + + return NULL; + } + + if (command != CCREQ_CONNECT) + return NULL; + + if (Q_strcmp(MSG_ReadString(), "QUAKE") != 0) + return NULL; + + if (MSG_ReadByte() != NET_PROTOCOL_VERSION) + { + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_REJECT); + MSG_WriteString(&net_message, "Incompatible version.\n"); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + return NULL; + } + +#ifdef BAN_TEST + // check for a ban + if (clientaddr.sa_family == AF_INET) + { + unsigned long testAddr; + testAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr; + if ((testAddr & banMask) == banAddr) + { + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_REJECT); + MSG_WriteString(&net_message, "You have been banned.\n"); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + return NULL; + } + } +#endif + + // see if this guy is already connected + for (s = net_activeSockets; s; s = s->next) + { + if (s->driver != net_driverlevel) + continue; + ret = dfunc.AddrCompare(&clientaddr, &s->addr); + if (ret >= 0) + { + // is this a duplicate connection reqeust? + if (ret == 0 && net_time - s->connecttime < 2.0) + { + // yes, so send a duplicate reply + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_ACCEPT); + dfunc.GetSocketAddr(s->socket, &newaddr); + MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr)); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + return NULL; + } + // it's somebody coming back in from a crash/disconnect + // so close the old qsocket and let their retry get them back in + NET_Close(s); + return NULL; + } + } + + // allocate a QSocket + sock = NET_NewQSocket (); + if (sock == NULL) + { + // no room; try to let him know + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_REJECT); + MSG_WriteString(&net_message, "Server is full.\n"); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + return NULL; + } + + // allocate a network socket + newsock = dfunc.OpenSocket(0); + if (newsock == -1) + { + NET_FreeQSocket(sock); + return NULL; + } + + // connect to the client + if (dfunc.Connect (newsock, &clientaddr) == -1) + { + dfunc.CloseSocket(newsock); + NET_FreeQSocket(sock); + return NULL; + } + + // everything is allocated, just fill in the details + sock->socket = newsock; + sock->landriver = net_landriverlevel; + sock->addr = clientaddr; + Q_strcpy(sock->address, dfunc.AddrToString(&clientaddr)); + + // send him back the info about the server connection he has been allocated + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREP_ACCEPT); + dfunc.GetSocketAddr(newsock, &newaddr); + MSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr)); +// MSG_WriteString(&net_message, dfunc.AddrToString(&newaddr)); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr); + SZ_Clear(&net_message); + + return sock; +} + +qsocket_t *Datagram_CheckNewConnections (void) +{ + qsocket_t *ret = NULL; + + for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) + if (net_landrivers[net_landriverlevel].initialized) + if ((ret = _Datagram_CheckNewConnections ()) != NULL) + break; + return ret; +} + + +static void _Datagram_SearchForHosts (qboolean xmit) +{ + int ret; + int n; + int i; + struct qsockaddr readaddr; + struct qsockaddr myaddr; + int control; + + dfunc.GetSocketAddr (dfunc.controlSock, &myaddr); + if (xmit) + { + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREQ_SERVER_INFO); + MSG_WriteString(&net_message, "QUAKE"); + MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize); + SZ_Clear(&net_message); + } + + while ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0) + { + if (ret < sizeof(int)) + continue; + net_message.cursize = ret; + + // don't answer our own query + if (dfunc.AddrCompare(&readaddr, &myaddr) >= 0) + continue; + + // is the cache full? + if (hostCacheCount == HOSTCACHESIZE) + continue; + + MSG_BeginReading (); + control = BigLong(*((int *)net_message.data)); + MSG_ReadLong(); + if (control == -1) + continue; + if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) + continue; + if ((control & NETFLAG_LENGTH_MASK) != ret) + continue; + + if (MSG_ReadByte() != CCREP_SERVER_INFO) + continue; + + dfunc.GetAddrFromName(MSG_ReadString(), &readaddr); + // search the cache for this server + for (n = 0; n < hostCacheCount; n++) + if (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0) + break; + + // is it already there? + if (n < hostCacheCount) + continue; + + // add it + hostCacheCount++; + Q_strcpy(hostcache[n].name, MSG_ReadString()); + Q_strcpy(hostcache[n].map, MSG_ReadString()); + hostcache[n].users = MSG_ReadByte(); + hostcache[n].maxusers = MSG_ReadByte(); + if (MSG_ReadByte() != NET_PROTOCOL_VERSION) + { + Q_strcpy(hostcache[n].cname, hostcache[n].name); + hostcache[n].cname[14] = 0; + Q_strcpy(hostcache[n].name, "*"); + Q_strcat(hostcache[n].name, hostcache[n].cname); + } + Q_memcpy(&hostcache[n].addr, &readaddr, sizeof(struct qsockaddr)); + hostcache[n].driver = net_driverlevel; + hostcache[n].ldriver = net_landriverlevel; + Q_strcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr)); + + // check for a name conflict + for (i = 0; i < hostCacheCount; i++) + { + if (i == n) + continue; + if (Q_strcasecmp (hostcache[n].name, hostcache[i].name) == 0) + { + i = Q_strlen(hostcache[n].name); + if (i < 15 && hostcache[n].name[i-1] > '8') + { + hostcache[n].name[i] = '0'; + hostcache[n].name[i+1] = 0; + } + else + hostcache[n].name[i-1]++; + i = -1; + } + } + } +} + +void Datagram_SearchForHosts (qboolean xmit) +{ + for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) + { + if (hostCacheCount == HOSTCACHESIZE) + break; + if (net_landrivers[net_landriverlevel].initialized) + _Datagram_SearchForHosts (xmit); + } +} + + +static qsocket_t *_Datagram_Connect (char *host) +{ + struct qsockaddr sendaddr; + struct qsockaddr readaddr; + qsocket_t *sock; + int newsock; + int ret; + int reps; + double start_time; + int control; + char *reason; + + // see if we can resolve the host name + if (dfunc.GetAddrFromName(host, &sendaddr) == -1) + return NULL; + + newsock = dfunc.OpenSocket (0); + if (newsock == -1) + return NULL; + + sock = NET_NewQSocket (); + if (sock == NULL) + goto ErrorReturn2; + sock->socket = newsock; + sock->landriver = net_landriverlevel; + + // connect to the host + if (dfunc.Connect (newsock, &sendaddr) == -1) + goto ErrorReturn; + + // send the connection request + Con_Printf("trying...\n"); SCR_UpdateScreen (); + start_time = net_time; + + for (reps = 0; reps < 3; reps++) + { + SZ_Clear(&net_message); + // save space for the header, filled in later + MSG_WriteLong(&net_message, 0); + MSG_WriteByte(&net_message, CCREQ_CONNECT); + MSG_WriteString(&net_message, "QUAKE"); + MSG_WriteByte(&net_message, NET_PROTOCOL_VERSION); + *((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK)); + dfunc.Write (newsock, net_message.data, net_message.cursize, &sendaddr); + SZ_Clear(&net_message); + do + { + ret = dfunc.Read (newsock, net_message.data, net_message.maxsize, &readaddr); + // if we got something, validate it + if (ret > 0) + { + // is it from the right place? + if (sfunc.AddrCompare(&readaddr, &sendaddr) != 0) + { +#ifdef DEBUG + Con_Printf("wrong reply address\n"); + Con_Printf("Expected: %s\n", StrAddr (&sendaddr)); + Con_Printf("Received: %s\n", StrAddr (&readaddr)); + SCR_UpdateScreen (); +#endif + ret = 0; + continue; + } + + if (ret < sizeof(int)) + { + ret = 0; + continue; + } + + net_message.cursize = ret; + MSG_BeginReading (); + + control = BigLong(*((int *)net_message.data)); + MSG_ReadLong(); + if (control == -1) + { + ret = 0; + continue; + } + if ((control & (~NETFLAG_LENGTH_MASK)) != NETFLAG_CTL) + { + ret = 0; + continue; + } + if ((control & NETFLAG_LENGTH_MASK) != ret) + { + ret = 0; + continue; + } + } + } + while (ret == 0 && (SetNetTime() - start_time) < 2.5); + if (ret) + break; + Con_Printf("still trying...\n"); SCR_UpdateScreen (); + start_time = SetNetTime(); + } + + if (ret == 0) + { + reason = "No Response"; + Con_Printf("%s\n", reason); + Q_strcpy(m_return_reason, reason); + goto ErrorReturn; + } + + if (ret == -1) + { + reason = "Network Error"; + Con_Printf("%s\n", reason); + Q_strcpy(m_return_reason, reason); + goto ErrorReturn; + } + + ret = MSG_ReadByte(); + if (ret == CCREP_REJECT) + { + reason = MSG_ReadString(); + Con_Printf(reason); + Q_strncpy(m_return_reason, reason, 31); + goto ErrorReturn; + } + + if (ret == CCREP_ACCEPT) + { + Q_memcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr)); + dfunc.SetSocketPort (&sock->addr, MSG_ReadLong()); + } + else + { + reason = "Bad Response"; + Con_Printf("%s\n", reason); + Q_strcpy(m_return_reason, reason); + goto ErrorReturn; + } + + dfunc.GetNameFromAddr (&sendaddr, sock->address); + + Con_Printf ("Connection accepted\n"); + sock->lastMessageTime = SetNetTime(); + + // switch the connection to the specified address + if (dfunc.Connect (newsock, &sock->addr) == -1) + { + reason = "Connect to Game failed"; + Con_Printf("%s\n", reason); + Q_strcpy(m_return_reason, reason); + goto ErrorReturn; + } + + m_return_onerror = false; + return sock; + +ErrorReturn: + NET_FreeQSocket(sock); +ErrorReturn2: + dfunc.CloseSocket(newsock); + if (m_return_onerror) + { + key_dest = key_menu; + m_state = m_return_state; + m_return_onerror = false; + } + return NULL; +} + +qsocket_t *Datagram_Connect (char *host) +{ + qsocket_t *ret = NULL; + + for (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++) + if (net_landrivers[net_landriverlevel].initialized) + if ((ret = _Datagram_Connect (host)) != NULL) + break; + return ret; +} diff --git a/project/jni/application/quake/source/net_dgrm.h b/project/jni/application/quake/source/net_dgrm.h new file mode 100644 index 000000000..da052e701 --- /dev/null +++ b/project/jni/application/quake/source/net_dgrm.h @@ -0,0 +1,34 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_dgrm.h + + +int Datagram_Init (void); +void Datagram_Listen (qboolean state); +void Datagram_SearchForHosts (qboolean xmit); +qsocket_t *Datagram_Connect (char *host); +qsocket_t *Datagram_CheckNewConnections (void); +int Datagram_GetMessage (qsocket_t *sock); +int Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data); +int Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data); +qboolean Datagram_CanSendMessage (qsocket_t *sock); +qboolean Datagram_CanSendUnreliableMessage (qsocket_t *sock); +void Datagram_Close (qsocket_t *sock); +void Datagram_Shutdown (void); diff --git a/project/jni/application/quake/source/net_loop.c b/project/jni/application/quake/source/net_loop.c new file mode 100644 index 000000000..f86f0a44f --- /dev/null +++ b/project/jni/application/quake/source/net_loop.c @@ -0,0 +1,270 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_loop.c + +#include "quakedef.h" +#include "net_loop.h" + +qboolean localconnectpending = false; +qsocket_t *loop_client = NULL; +qsocket_t *loop_server = NULL; + +int Loop_Init (void) +{ + if (cls.state == ca_dedicated) + return -1; + return 0; +} + + +void Loop_Shutdown (void) +{ +} + + +void Loop_Listen (qboolean state) +{ +} + + +void Loop_SearchForHosts (qboolean xmit) +{ + + if (!sv.active){ + return; + } + + hostCacheCount = 1; + if (Q_strcmp(hostname.string, "UNNAMED") == 0) + Q_strcpy(hostcache[0].name, "local"); + else + Q_strcpy(hostcache[0].name, hostname.string); + Q_strcpy(hostcache[0].map, sv.name); + hostcache[0].users = net_activeconnections; + hostcache[0].maxusers = svs.maxclients; + hostcache[0].driver = net_driverlevel; + Q_strcpy(hostcache[0].cname, "local"); +} + + +qsocket_t *Loop_Connect (char *host) +{ + if (Q_strcmp(host,"local") != 0) + return NULL; + + GpError("Loop Connect",0); + + localconnectpending = true; + + if (!loop_client) + { + if ((loop_client = NET_NewQSocket ()) == NULL) + { + GpError("Loop Connect - client Error",0); + Con_Printf("Loop_Connect: no qsocket available\n"); + return NULL; + } + Q_strcpy (loop_client->address, "localhost"); + } + loop_client->receiveMessageLength = 0; + loop_client->sendMessageLength = 0; + loop_client->canSend = true; + + if (!loop_server) + { + if ((loop_server = NET_NewQSocket ()) == NULL) + { + GpError("Loop Connect - server Error",0); + Con_Printf("Loop_Connect: no qsocket available\n"); + return NULL; + } + Q_strcpy (loop_server->address, "LOCAL"); + } + loop_server->receiveMessageLength = 0; + loop_server->sendMessageLength = 0; + loop_server->canSend = true; + + loop_client->driverdata = (void *)loop_server; + loop_server->driverdata = (void *)loop_client; + + return loop_client; +} + + +qsocket_t *Loop_CheckNewConnections (void) +{ + GpError("Loop_CheckNewConnections",0); + if (!localconnectpending){ + GpError("Loop_CheckNewConnections NULL",0); + return NULL; + } + + localconnectpending = false; + loop_server->sendMessageLength = 0; + loop_server->receiveMessageLength = 0; + loop_server->canSend = true; + loop_client->sendMessageLength = 0; + loop_client->receiveMessageLength = 0; + loop_client->canSend = true; + GpError("Loop_CheckNewConnections done",0); + return loop_server; +} + + +static int IntAlign(int value) +{ + return (value + (sizeof(int) - 1)) & (~(sizeof(int) - 1)); +} + + +int Loop_GetMessage (qsocket_t *sock) +{ + int ret; + int length; + + + if (sock->receiveMessageLength == 0){ + return 0; + } + + ret = sock->receiveMessage[0]; + + + length = sock->receiveMessage[1] + (sock->receiveMessage[2] << 8); + // alignment byte skipped here + SZ_Clear (&net_message); + SZ_Write (&net_message, &sock->receiveMessage[4], length); + + length = IntAlign(length + 4); + sock->receiveMessageLength -= length; + + if (sock->receiveMessageLength) + Q_memcpy(sock->receiveMessage, &sock->receiveMessage[length], sock->receiveMessageLength); + + if (sock->driverdata && ret == 1) + ((qsocket_t *)sock->driverdata)->canSend = true; + + return ret; +} + + +int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data) +{ + byte *buffer; + int *bufferLength; + + + if (!sock->driverdata){ + return -1; + } + + + bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength; + + if ((*bufferLength + data->cursize + 4) > NET_MAXMESSAGE){ + Sys_Error("Loop_SendMessage: overflow\n"); + } + + buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength; + + // message type + *buffer++ = 1; + + // length + *buffer++ = data->cursize & 0xff; + *buffer++ = data->cursize >> 8; + + // align + buffer++; + + // message + Q_memcpy(buffer, data->data, data->cursize); + *bufferLength = IntAlign(*bufferLength + data->cursize + 4); + + + sock->canSend = false; + return 1; +} + + +int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data) +{ + byte *buffer; + int *bufferLength; + + + if (!sock->driverdata){ + return -1; + } + + bufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength; + + if ((*bufferLength + data->cursize + sizeof(byte) + sizeof(short)) > NET_MAXMESSAGE){ + return 0; + } + + buffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength; + + // message type + *buffer++ = 2; + + // length + *buffer++ = data->cursize & 0xff; + *buffer++ = data->cursize >> 8; + + // align + buffer++; + + // message + Q_memcpy(buffer, data->data, data->cursize); + *bufferLength = IntAlign(*bufferLength + data->cursize + 4); + + GpError("Loop_SUM : done",2); + return 1; +} + + +qboolean Loop_CanSendMessage (qsocket_t *sock) +{ + if (!sock->driverdata){ + return false; + } + return sock->canSend; +} + + +qboolean Loop_CanSendUnreliableMessage (qsocket_t *sock) +{ + return true; +} + + +void Loop_Close (qsocket_t *sock) +{ + if (sock->driverdata) + ((qsocket_t *)sock->driverdata)->driverdata = NULL; + sock->receiveMessageLength = 0; + sock->sendMessageLength = 0; + sock->canSend = true; + if (sock == loop_client) + loop_client = NULL; + else + loop_server = NULL; +} diff --git a/project/jni/application/quake/source/net_loop.h b/project/jni/application/quake/source/net_loop.h new file mode 100644 index 000000000..210f40daa --- /dev/null +++ b/project/jni/application/quake/source/net_loop.h @@ -0,0 +1,33 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_loop.h + +int Loop_Init (void); +void Loop_Listen (qboolean state); +void Loop_SearchForHosts (qboolean xmit); +qsocket_t *Loop_Connect (char *host); +qsocket_t *Loop_CheckNewConnections (void); +int Loop_GetMessage (qsocket_t *sock); +int Loop_SendMessage (qsocket_t *sock, sizebuf_t *data); +int Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data); +qboolean Loop_CanSendMessage (qsocket_t *sock); +qboolean Loop_CanSendUnreliableMessage (qsocket_t *sock); +void Loop_Close (qsocket_t *sock); +void Loop_Shutdown (void); diff --git a/project/jni/application/quake/source/net_main.c b/project/jni/application/quake/source/net_main.c new file mode 100644 index 000000000..407de07e9 --- /dev/null +++ b/project/jni/application/quake/source/net_main.c @@ -0,0 +1,1037 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_main.c + +#include "quakedef.h" +#include "net_vcr.h" + +qsocket_t *net_activeSockets = NULL; +qsocket_t *net_freeSockets = NULL; +int net_numsockets = 0; + +qboolean serialAvailable = false; +qboolean ipxAvailable = false; +qboolean tcpipAvailable = false; + +int net_hostport; +int DEFAULTnet_hostport = 26000; + +char my_ipx_address[NET_NAMELEN]; +char my_tcpip_address[NET_NAMELEN]; + +void (*GetComPortConfig) (int portNumber, int *port, int *irq, int *baud, qboolean *useModem); +void (*SetComPortConfig) (int portNumber, int port, int irq, int baud, qboolean useModem); +void (*GetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup); +void (*SetModemConfig) (int portNumber, char *dialType, char *clear, char *init, char *hangup); + +static qboolean listening = false; + +qboolean slistInProgress = false; +qboolean slistSilent = false; +qboolean slistLocal = true; +static double slistStartTime; +static int slistLastShown; + +static void Slist_Send(void); +static void Slist_Poll(void); +PollProcedure slistSendProcedure = {NULL, 0.0, Slist_Send}; +PollProcedure slistPollProcedure = {NULL, 0.0, Slist_Poll}; + + +sizebuf_t net_message; +int net_activeconnections = 0; + +int messagesSent = 0; +int messagesReceived = 0; +int unreliableMessagesSent = 0; +int unreliableMessagesReceived = 0; + +cvar_t net_messagetimeout = {"net_messagetimeout","300"}; +cvar_t hostname = {"hostname", "UNNAMED"}; + +qboolean configRestored = false; +cvar_t config_com_port = {"_config_com_port", "0x3f8", true}; +cvar_t config_com_irq = {"_config_com_irq", "4", true}; +cvar_t config_com_baud = {"_config_com_baud", "57600", true}; +cvar_t config_com_modem = {"_config_com_modem", "1", true}; +cvar_t config_modem_dialtype = {"_config_modem_dialtype", "T", true}; +cvar_t config_modem_clear = {"_config_modem_clear", "ATZ", true}; +cvar_t config_modem_init = {"_config_modem_init", "", true}; +cvar_t config_modem_hangup = {"_config_modem_hangup", "AT H", true}; + +#ifdef IDGODS +cvar_t idgods = {"idgods", "0"}; +#endif + +int vcrFile = -1; +qboolean recording = false; + +// these two macros are to make the code more readable +#define sfunc net_drivers[sock->driver] +#define dfunc net_drivers[net_driverlevel] + +int net_driverlevel; + + +double net_time; + +double SetNetTime(void) +{ + net_time = Sys_FloatTime(); + return net_time; +} + + +/* +=================== +NET_NewQSocket + +Called by drivers when a new communications endpoint is required +The sequence and buffer fields will be filled in properly +=================== +*/ +qsocket_t *NET_NewQSocket (void) +{ + qsocket_t *sock; + + GpError("NET_NewQSocket",0); + + if (net_freeSockets == NULL){ + return NULL; + } + + if (net_activeconnections >= svs.maxclients){ + return NULL; + } + + // get one from free list + sock = net_freeSockets; + net_freeSockets = sock->next; + + // add it to active list + sock->next = net_activeSockets; + net_activeSockets = sock; + + sock->disconnected = false; + sock->connecttime = net_time; + Q_strcpy (sock->address,"UNSET ADDRESS"); + sock->driver = net_driverlevel; + sock->socket = 0; + sock->driverdata = NULL; + sock->canSend = true; + sock->sendNext = false; + sock->lastMessageTime = net_time; + sock->ackSequence = 0; + sock->sendSequence = 0; + sock->unreliableSendSequence = 0; + sock->sendMessageLength = 0; + sock->receiveSequence = 0; + sock->unreliableReceiveSequence = 0; + sock->receiveMessageLength = 0; + + return sock; +} + + +void NET_FreeQSocket(qsocket_t *sock) +{ + qsocket_t *s; + + GpError("NET_FreeQSocket",0); + + // remove it from active list + if (sock == net_activeSockets) + net_activeSockets = net_activeSockets->next; + else + { + for (s = net_activeSockets; s; s = s->next) + if (s->next == sock) + { + s->next = sock->next; + break; + } + if (!s) + Sys_Error ("NET_FreeQSocket: not active\n"); + } + + // add it to free list + sock->next = net_freeSockets; + net_freeSockets = sock; + sock->disconnected = true; + +} + + +static void NET_Listen_f (void) +{ + if (Cmd_Argc () != 2) + { + Con_Printf ("\"listen\" is \"%u\"\n", listening ? 1 : 0); + return; + } + + listening = Q_atoi(Cmd_Argv(1)) ? true : false; + + for (net_driverlevel=0 ; net_driverlevel svs.maxclientslimit) + { + n = svs.maxclientslimit; + Con_Printf ("\"maxplayers\" set to \"%u\"\n", n); + } + + if ((n == 1) && listening) + Cbuf_AddText ("listen 0\n"); + + if ((n > 1) && (!listening)) + Cbuf_AddText ("listen 1\n"); + + svs.maxclients = n; + if (n == 1) + Cvar_Set ("deathmatch", "0"); + else + Cvar_Set ("deathmatch", "1"); +} + + +static void NET_Port_f (void) +{ + int n; + + if (Cmd_Argc () != 2) + { + Con_Printf ("\"port\" is \"%u\"\n", net_hostport); + return; + } + + n = Q_atoi(Cmd_Argv(1)); + if (n < 1 || n > 65534) + { + Con_Printf ("Bad value, must be between 1 and 65534\n"); + return; + } + + DEFAULTnet_hostport = n; + net_hostport = n; + + if (listening) + { + // force a change to the new port + Cbuf_AddText ("listen 0\n"); + Cbuf_AddText ("listen 1\n"); + } +} + + +static void PrintSlistHeader(void) +{ + Con_Printf("Server Map Users\n"); + Con_Printf("--------------- --------------- -----\n"); + slistLastShown = 0; +} + + +static void PrintSlist(void) +{ + int n; + + for (n = slistLastShown; n < hostCacheCount; n++) + { + if (hostcache[n].maxusers) + Con_Printf("%-15.15s %-15.15s %2u/%2u\n", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers); + else + Con_Printf("%-15.15s %-15.15s\n", hostcache[n].name, hostcache[n].map); + } + slistLastShown = n; +} + + +static void PrintSlistTrailer(void) +{ + if (hostCacheCount) + Con_Printf("== end list ==\n\n"); + else + Con_Printf("No Quake servers found.\n\n"); +} + + +void NET_Slist_f (void) +{ + if (slistInProgress) + return; + + if (! slistSilent) + { + Con_Printf("Looking for Quake servers...\n"); + PrintSlistHeader(); + } + + slistInProgress = true; + slistStartTime = Sys_FloatTime(); + + SchedulePollProcedure(&slistSendProcedure, 0.0); + SchedulePollProcedure(&slistPollProcedure, 0.1); + + hostCacheCount = 0; +} + + +static void Slist_Send(void) +{ + for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++) + { + if (!slistLocal && net_driverlevel == 0) + continue; + if (net_drivers[net_driverlevel].initialized == false) + continue; + dfunc.SearchForHosts (true); + } + + if ((Sys_FloatTime() - slistStartTime) < 0.5) + SchedulePollProcedure(&slistSendProcedure, 0.75); +} + + +static void Slist_Poll(void) +{ + for (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++) + { + if (!slistLocal && net_driverlevel == 0) + continue; + if (net_drivers[net_driverlevel].initialized == false) + continue; + dfunc.SearchForHosts (false); + } + + if (! slistSilent) + PrintSlist(); + + if ((Sys_FloatTime() - slistStartTime) < 1.5) + { + SchedulePollProcedure(&slistPollProcedure, 0.1); + return; + } + + if (! slistSilent) + PrintSlistTrailer(); + slistInProgress = false; + slistSilent = false; + slistLocal = true; +} + + +/* +=================== +NET_Connect +=================== +*/ + +int hostCacheCount = 0; +hostcache_t hostcache[HOSTCACHESIZE]; + +qsocket_t *NET_Connect (char *host) +{ + qsocket_t *ret; + int n; + int numdrivers = net_numdrivers; + + GpError("NET_Connect",0); + + SetNetTime(); + + if (host && *host == 0) + host = NULL; + + if (host) + { + if (Q_strcasecmp (host, "local") == 0) + { + numdrivers = 1; + goto JustDoIt; + } + + if (hostCacheCount) + { + for (n = 0; n < hostCacheCount; n++) + if (Q_strcasecmp (host, hostcache[n].name) == 0) + { + host = hostcache[n].cname; + break; + } + if (n < hostCacheCount) + goto JustDoIt; + } + } + + slistSilent = host ? true : false; + NET_Slist_f (); + + while(slistInProgress) + NET_Poll(); + + if (host == NULL) + { + if (hostCacheCount != 1) + return NULL; + host = hostcache[0].cname; + Con_Printf("Connecting to...\n%s @ %s\n\n", hostcache[0].name, host); + } + + if (hostCacheCount) + for (n = 0; n < hostCacheCount; n++) + if (Q_strcasecmp (host, hostcache[n].name) == 0) + { + host = hostcache[n].cname; + break; + } + +JustDoIt: + for (net_driverlevel=0 ; net_driverleveladdress, NET_NAMELEN); + } + return ret; + } + } + + if (recording) + { + vcrConnect.time = host_time; + vcrConnect.op = VCR_OP_CONNECT; + vcrConnect.session = 0; + Sys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect)); + } + + return NULL; +} + +/* +=================== +NET_Close +=================== +*/ +void NET_Close (qsocket_t *sock) +{ + if (!sock) + return; + + if (sock->disconnected) + return; + + SetNetTime(); + + // call the driver_Close function + sfunc.Close (sock); + + NET_FreeQSocket(sock); +} + + +/* +================= +NET_GetMessage + +If there is a complete message, return it in net_message + +returns 0 if no data is waiting +returns 1 if a message was received +returns -1 if connection is invalid +================= +*/ + +struct +{ + double time; + int op; + long session; + int ret; + int len; +} vcrGetMessage; + +extern void PrintStats(qsocket_t *s); + +int NET_GetMessage (qsocket_t *sock) +{ + int ret; + + GpError("NET_GetMessage",0); + + if (!sock){ + GpError("NET_GetMessage fail",2); + return -1; + } + + if (sock->disconnected) + { + GpError("NET_GetMessage discon",2); + Con_Printf("NET_GetMessage: disconnected socket\n"); + return -1; + } + + SetNetTime(); + + ret = sfunc.QGetMessage(sock); + + // see if this connection has timed out + if (ret == 0 && sock->driver) + { + if (net_time - sock->lastMessageTime > net_messagetimeout.value) + { + GpError("NET_GetMessage timeout",2); + NET_Close(sock); + return -1; + } + } + + + if (ret > 0) + { + if (sock->driver) + { + sock->lastMessageTime = net_time; + if (ret == 1) + messagesReceived++; + else if (ret == 2) + unreliableMessagesReceived++; + } + + if (recording) + { + vcrGetMessage.time = host_time; + vcrGetMessage.op = VCR_OP_GETMESSAGE; + vcrGetMessage.session = (long)sock; + vcrGetMessage.ret = ret; + vcrGetMessage.len = net_message.cursize; + Sys_FileWrite (vcrFile, &vcrGetMessage, 24); + Sys_FileWrite (vcrFile, net_message.data, net_message.cursize); + } + } + else + { + if (recording) + { + vcrGetMessage.time = host_time; + vcrGetMessage.op = VCR_OP_GETMESSAGE; + vcrGetMessage.session = (long)sock; + vcrGetMessage.ret = ret; + Sys_FileWrite (vcrFile, &vcrGetMessage, 20); + } + } + + return ret; +} + + +/* +================== +NET_SendMessage + +Try to send a complete length+message unit over the reliable stream. +returns 0 if the message cannot be delivered reliably, but the connection + is still considered valid +returns 1 if the message was sent properly +returns -1 if the connection died +================== +*/ +struct +{ + double time; + int op; + long session; + int r; +} vcrSendMessage; + +int NET_SendMessage (qsocket_t *sock, sizebuf_t *data) +{ + int r; + + GpError("NET_SendMessage",0); + + if (!sock){ + GpError("NET_SendMessage - fail",0); + return -1; + } + + if (sock->disconnected) + { + GpError("NET_SendMessage - disconnected socket",0); + Con_Printf("NET_SendMessage: disconnected socket\n"); + return -1; + } + + SetNetTime(); + r = sfunc.QSendMessage(sock, data); + + if (r == 1 && sock->driver){ + messagesSent++; + + } + + if (recording) + { + vcrSendMessage.time = host_time; + vcrSendMessage.op = VCR_OP_SENDMESSAGE; + vcrSendMessage.session = (long)sock; + vcrSendMessage.r = r; + Sys_FileWrite (vcrFile, &vcrSendMessage, 20); + } + + return r; +} + + +int NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data) +{ + int r; + + GpError("NET_SendUnreliableMessage",2); + if (!sock){ + GpError("NET_SRM : !sock",2); + return -1; + } + + if (sock->disconnected) + { + + GpError("NET_SRM : sock->disconnected",2); + + Con_Printf("NET_SendMessage: disconnected socket\n"); + return -1; + } + + SetNetTime(); + r = sfunc.SendUnreliableMessage(sock, data); + + if (r == 1 && sock->driver) + unreliableMessagesSent++; + + if (recording) + { + vcrSendMessage.time = host_time; + vcrSendMessage.op = VCR_OP_SENDMESSAGE; + vcrSendMessage.session = (long)sock; + vcrSendMessage.r = r; + Sys_FileWrite (vcrFile, &vcrSendMessage, 20); + } + + return r; +} + + +/* +================== +NET_CanSendMessage + +Returns true or false if the given qsocket can currently accept a +message to be transmitted. +================== +*/ +qboolean NET_CanSendMessage (qsocket_t *sock) +{ + int r; + + if (!sock) + return false; + + if (sock->disconnected) + return false; + + SetNetTime(); + + r = sfunc.CanSendMessage(sock); + + if (recording) + { + vcrSendMessage.time = host_time; + vcrSendMessage.op = VCR_OP_CANSENDMESSAGE; + vcrSendMessage.session = (long)sock; + vcrSendMessage.r = r; + Sys_FileWrite (vcrFile, &vcrSendMessage, 20); + } + + return r; +} + + +int NET_SendToAll(sizebuf_t *data, int blocktime) +{ + double start; + int i; + int count = 0; + qboolean state1 [MAX_SCOREBOARD]; + qboolean state2 [MAX_SCOREBOARD]; + + for (i=0, host_client = svs.clients ; inetconnection) + continue; + if (host_client->active) + { + if (host_client->netconnection->driver == 0) + { + NET_SendMessage(host_client->netconnection, data); + state1[i] = true; + state2[i] = true; + continue; + } + count++; + state1[i] = false; + state2[i] = false; + } + else + { + state1[i] = true; + state2[i] = true; + } + } + + start = Sys_FloatTime(); + while (count) + { + count = 0; + for (i=0, host_client = svs.clients ; inetconnection)) + { + state1[i] = true; + NET_SendMessage(host_client->netconnection, data); + } + else + { + NET_GetMessage (host_client->netconnection); + } + count++; + continue; + } + + if (! state2[i]) + { + if (NET_CanSendMessage (host_client->netconnection)) + { + state2[i] = true; + } + else + { + NET_GetMessage (host_client->netconnection); + } + count++; + continue; + } + } + if ((Sys_FloatTime() - start) > blocktime) + break; + } + return count; +} + + +//============================================================================= + +/* +==================== +NET_Init +==================== +*/ + +void NET_Init (void) +{ + int i; + int controlSocket; + qsocket_t *s; + puts("here"); + if (COM_CheckParm("-playback")) + { + net_numdrivers = 1; + net_drivers[0].Init = VCR_Init; + } + + if (COM_CheckParm("-record")) + recording = true; + + i = COM_CheckParm ("-port"); + if (!i) + i = COM_CheckParm ("-udpport"); + if (!i) + i = COM_CheckParm ("-ipxport"); + + if (i) + { + if (i < com_argc-1) + DEFAULTnet_hostport = Q_atoi (com_argv[i+1]); + else + Sys_Error ("NET_Init: you must specify a number after -port"); + } + net_hostport = DEFAULTnet_hostport; + puts("here1"); + if (COM_CheckParm("-listen") || cls.state == ca_dedicated) + listening = true; + net_numsockets = svs.maxclientslimit; + if (cls.state != ca_dedicated) + net_numsockets++; + + puts("here2"); + SetNetTime(); + puts("here3"); + + for (i = 0; i < net_numsockets; i++) + { + s = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), "qsocket"); + s->next = net_freeSockets; + net_freeSockets = s; + s->disconnected = true; + } + puts("here4"); + + // allocate space for network message buffer + SZ_Alloc (&net_message, NET_MAXMESSAGE); + + Cvar_RegisterVariable (&net_messagetimeout); + Cvar_RegisterVariable (&hostname); + Cvar_RegisterVariable (&config_com_port); + Cvar_RegisterVariable (&config_com_irq); + Cvar_RegisterVariable (&config_com_baud); + Cvar_RegisterVariable (&config_com_modem); + Cvar_RegisterVariable (&config_modem_dialtype); + Cvar_RegisterVariable (&config_modem_clear); + Cvar_RegisterVariable (&config_modem_init); + Cvar_RegisterVariable (&config_modem_hangup); +#ifdef IDGODS + Cvar_RegisterVariable (&idgods); +#endif + + Cmd_AddCommand ("slist", NET_Slist_f); + Cmd_AddCommand ("listen", NET_Listen_f); + Cmd_AddCommand ("maxplayers", MaxPlayers_f); + Cmd_AddCommand ("port", NET_Port_f); + + puts("here5"); + + // initialize all the drivers + for (net_driverlevel=0 ; net_driverlevelnext) + NET_Close(sock); + +// +// shutdown the drivers +// + for (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++) + { + if (net_drivers[net_driverlevel].initialized == true) + { + net_drivers[net_driverlevel].Shutdown (); + net_drivers[net_driverlevel].initialized = false; + } + } + + if (vcrFile != -1) + { + Con_Printf ("Closing vcrfile.\n"); + Sys_FileClose(vcrFile); + } +} + + +static PollProcedure *pollProcedureList = NULL; + +void NET_Poll(void) +{ + PollProcedure *pp; + qboolean useModem; + + if (!configRestored) + { + if (serialAvailable) + { + if (config_com_modem.value == 1.0) + useModem = true; + else + useModem = false; + SetComPortConfig (0, (int)config_com_port.value, (int)config_com_irq.value, (int)config_com_baud.value, useModem); + SetModemConfig (0, config_modem_dialtype.string, config_modem_clear.string, config_modem_init.string, config_modem_hangup.string); + } + configRestored = true; + } + + SetNetTime(); + + for (pp = pollProcedureList; pp; pp = pp->next) + { + if (pp->nextTime > net_time) + break; + pollProcedureList = pp->next; + pp->procedure(pp->arg); + } +} + + +void SchedulePollProcedure(PollProcedure *proc, double timeOffset) +{ + PollProcedure *pp, *prev; + + proc->nextTime = Sys_FloatTime() + timeOffset; + for (pp = pollProcedureList, prev = NULL; pp; pp = pp->next) + { + if (pp->nextTime >= proc->nextTime) + break; + prev = pp; + } + + if (prev == NULL) + { + proc->next = pollProcedureList; + pollProcedureList = proc; + return; + } + + proc->next = pp; + prev->next = proc; +} + + +#ifdef IDGODS +#define IDNET 0xc0f62800 + +qboolean IsID(struct qsockaddr *addr) +{ + if (idgods.value == 0.0) + return false; + + if (addr->sa_family != 2) + return false; + + if ((BigLong(*(int *)&addr->sa_data[2]) & 0xffffff00) == IDNET) + return true; + return false; +} +#endif diff --git a/project/jni/application/quake/source/net_ser.h b/project/jni/application/quake/source/net_ser.h new file mode 100644 index 000000000..250394fc8 --- /dev/null +++ b/project/jni/application/quake/source/net_ser.h @@ -0,0 +1,33 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_ser.h + +int Serial_Init (void); +void Serial_Listen (qboolean state); +void Serial_SearchForHosts (qboolean xmit); +qsocket_t *Serial_Connect (char *host); +qsocket_t *Serial_CheckNewConnections (void); +int Serial_GetMessage (qsocket_t *sock); +int Serial_SendMessage (qsocket_t *sock, sizebuf_t *data); +int Serial_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data); +qboolean Serial_CanSendMessage (qsocket_t *sock); +qboolean Serial_CanSendUnreliableMessage (qsocket_t *sock); +void Serial_Close (qsocket_t *sock); +void Serial_Shutdown (void); diff --git a/project/jni/application/quake/source/net_udp.c b/project/jni/application/quake/source/net_udp.c new file mode 100644 index 000000000..c4646ce11 --- /dev/null +++ b/project/jni/application/quake/source/net_udp.c @@ -0,0 +1,422 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_udp.c + +#include "quakedef.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __sun__ +#include +#endif + +#ifdef NeXT +#include +#endif + +extern int gethostname (char *, int); +extern int close (int); + +extern cvar_t hostname; + +static int net_acceptsocket = -1; // socket for fielding new connections +static int net_controlsocket; +static int net_broadcastsocket = 0; +static struct qsockaddr broadcastaddr; + +static unsigned long myAddr; + +#include "net_udp.h" + +//============================================================================= + +int UDP_Init (void) +{ + struct hostent *local; + char buff[MAXHOSTNAMELEN]; + struct qsockaddr addr; + char *colon; + + if (COM_CheckParm ("-noudp")) + return -1; + + // determine my name & address + //gethostname(buff, MAXHOSTNAMELEN); + //local = gethostbyname(buff); + sprintf(buff,"gp2x"); + // myAddr = *(int *)local->h_addr_list[0]; + // myAddr=htonl((192 << 24) | (168 << 16) | (0 << 8) | 2); + myAddr=htonl((10 << 24) | (1 << 16) | (0 << 8) | 2); + // if the quake hostname isn't set, set it to the machine name + if (Q_strcmp(hostname.string, "UNNAMED") == 0) + { + buff[15] = 0; + Cvar_Set ("hostname", buff); + } + + if ((net_controlsocket = UDP_OpenSocket (0)) == -1) + Sys_Error("UDP_Init: Unable to open control socket\n"); + + ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET; + ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST; + ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons(net_hostport); + + UDP_GetSocketAddr (net_controlsocket, &addr); + Q_strcpy(my_tcpip_address, UDP_AddrToString (&addr)); + colon = Q_strrchr (my_tcpip_address, ':'); + if (colon) + *colon = 0; + + Con_Printf("UDP Initialized\n"); + tcpipAvailable = true; + + return net_controlsocket; +} + +//============================================================================= + +void UDP_Shutdown (void) +{ + UDP_Listen (false); + UDP_CloseSocket (net_controlsocket); +} + +//============================================================================= + +void UDP_Listen (qboolean state) +{ + // enable listening + if (state) + { + if (net_acceptsocket != -1) + return; + if ((net_acceptsocket = UDP_OpenSocket (net_hostport)) == -1) + Sys_Error ("UDP_Listen: Unable to open accept socket\n"); + return; + } + + // disable listening + if (net_acceptsocket == -1) + return; + UDP_CloseSocket (net_acceptsocket); + net_acceptsocket = -1; +} + +//============================================================================= + +int UDP_OpenSocket (int port) +{ + int newsocket; + struct sockaddr_in address; + qboolean _true = true; + + if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + return -1; + +#if 0 + if (ioctl (newsocket, FIONBIO, (char *)&_true) == -1) + goto ErrorReturn; +#endif + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(port); + if( bind (newsocket, (void *)&address, sizeof(address)) == -1) + goto ErrorReturn; + + return newsocket; + +ErrorReturn: + close (newsocket); + return -1; +} + +//============================================================================= + +int UDP_CloseSocket (int socket) +{ + if (socket == net_broadcastsocket) + net_broadcastsocket = 0; + return close (socket); +} + + +//============================================================================= +/* +============ +PartialIPAddress + +this lets you type only as much of the net address as required, using +the local network components to fill in the rest +============ +*/ +static int PartialIPAddress (char *in, struct qsockaddr *hostaddr) +{ + char buff[256]; + char *b; + int addr; + int num; + int mask; + int run; + int port; + + buff[0] = '.'; + b = buff; + strcpy(buff+1, in); + if (buff[1] == '.') + b++; + + addr = 0; + mask=-1; + while (*b == '.') + { + b++; + num = 0; + run = 0; + while (!( *b < '0' || *b > '9')) + { + num = num*10 + *b++ - '0'; + if (++run > 3) + return -1; + } + if ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0) + return -1; + if (num < 0 || num > 255) + return -1; + mask<<=8; + addr = (addr<<8) + num; + } + + if (*b++ == ':') + port = Q_atoi(b); + else + port = net_hostport; + + hostaddr->sa_family = AF_INET; + ((struct sockaddr_in *)hostaddr)->sin_port = htons((short)port); + ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr); + + return 0; +} +//============================================================================= + +int UDP_Connect (int socket, struct qsockaddr *addr) +{ + return 0; +} + +//============================================================================= + +int UDP_CheckNewConnections (void) +{ + unsigned long available; + + if (net_acceptsocket == -1) + return -1; + + if (ioctl (net_acceptsocket, FIONREAD, &available) == -1) + Sys_Error ("UDP: ioctlsocket (FIONREAD) failed\n"); + if (available) + return net_acceptsocket; + return -1; +} + +//============================================================================= + +int UDP_Read (int socket, byte *buf, int len, struct qsockaddr *addr) +{ + int addrlen = sizeof (struct qsockaddr); + int ret; + + ret = recvfrom (socket, buf, len, 0, (struct sockaddr *)addr, &addrlen); + if (ret == -1 && (errno == EWOULDBLOCK || errno == ECONNREFUSED)) + return 0; + return ret; +} + +//============================================================================= + +int UDP_MakeSocketBroadcastCapable (int socket) +{ + int i = 1; + + // make this socket broadcast capable + if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0) + return -1; + net_broadcastsocket = socket; + + return 0; +} + +//============================================================================= + +int UDP_Broadcast (int socket, byte *buf, int len) +{ + int ret; + + if (socket != net_broadcastsocket) + { + if (net_broadcastsocket != 0) + Sys_Error("Attempted to use multiple broadcasts sockets\n"); + ret = UDP_MakeSocketBroadcastCapable (socket); + if (ret == -1) + { + Con_Printf("Unable to make socket broadcast capable\n"); + return ret; + } + } + + return UDP_Write (socket, buf, len, &broadcastaddr); +} + +//============================================================================= + +int UDP_Write (int socket, byte *buf, int len, struct qsockaddr *addr) +{ + int ret; + + ret = sendto (socket, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr)); + if (ret == -1 && errno == EWOULDBLOCK) + return 0; + return ret; +} + +//============================================================================= + +char *UDP_AddrToString (struct qsockaddr *addr) +{ + static char buffer[22]; + int haddr; + + haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr); + sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port)); + return buffer; +} + +//============================================================================= + +int UDP_StringToAddr (char *string, struct qsockaddr *addr) +{ + int ha1, ha2, ha3, ha4, hp; + int ipaddr; + + sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp); + ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr); + ((struct sockaddr_in *)addr)->sin_port = htons(hp); + return 0; +} + +//============================================================================= + +int UDP_GetSocketAddr (int socket, struct qsockaddr *addr) +{ + int addrlen = sizeof(struct qsockaddr); + unsigned int a; + + Q_memset(addr, 0, sizeof(struct qsockaddr)); + getsockname(socket, (struct sockaddr *)addr, &addrlen); + a = ((struct sockaddr_in *)addr)->sin_addr.s_addr; + if (a == 0 || a == inet_addr("127.0.0.1")) + ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr; + + return 0; +} + +//============================================================================= + +int UDP_GetNameFromAddr (struct qsockaddr *addr, char *name) +{ + /* + struct hostent *hostentry; + + hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET); + if (hostentry) + { + Q_strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1); + return 0; + } + + Q_strcpy (name, UDP_AddrToString (addr)); + return 0; + */ + sprintf(name,"gp2x"); + return 0; +} + +//============================================================================= + +int UDP_GetAddrFromName(char *name, struct qsockaddr *addr) +{ + struct hostent *hostentry; + + if (name[0] >= '0' && name[0] <= '9') + return PartialIPAddress (name, addr); + + // hostentry = gethostbyname (name); + // if (!hostentry) + // return -1; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_port = htons(net_hostport); + // ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; + ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr; + + return 0; +} + +//============================================================================= + +int UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2) +{ + if (addr1->sa_family != addr2->sa_family) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port) + return 1; + + return 0; +} + +//============================================================================= + +int UDP_GetSocketPort (struct qsockaddr *addr) +{ + return ntohs(((struct sockaddr_in *)addr)->sin_port); +} + + +int UDP_SetSocketPort (struct qsockaddr *addr, int port) +{ + ((struct sockaddr_in *)addr)->sin_port = htons(port); + return 0; +} + +//============================================================================= diff --git a/project/jni/application/quake/source/net_udp.h b/project/jni/application/quake/source/net_udp.h new file mode 100644 index 000000000..75303011c --- /dev/null +++ b/project/jni/application/quake/source/net_udp.h @@ -0,0 +1,39 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_udp.h + +int UDP_Init (void); +void UDP_Shutdown (void); +void UDP_Listen (qboolean state); +int UDP_OpenSocket (int port); +int UDP_CloseSocket (int socket); +int UDP_Connect (int socket, struct qsockaddr *addr); +int UDP_CheckNewConnections (void); +int UDP_Read (int socket, byte *buf, int len, struct qsockaddr *addr); +int UDP_Write (int socket, byte *buf, int len, struct qsockaddr *addr); +int UDP_Broadcast (int socket, byte *buf, int len); +char *UDP_AddrToString (struct qsockaddr *addr); +int UDP_StringToAddr (char *string, struct qsockaddr *addr); +int UDP_GetSocketAddr (int socket, struct qsockaddr *addr); +int UDP_GetNameFromAddr (struct qsockaddr *addr, char *name); +int UDP_GetAddrFromName (char *name, struct qsockaddr *addr); +int UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2); +int UDP_GetSocketPort (struct qsockaddr *addr); +int UDP_SetSocketPort (struct qsockaddr *addr, int port); diff --git a/project/jni/application/quake/source/net_vcr.c b/project/jni/application/quake/source/net_vcr.c new file mode 100644 index 000000000..283390958 --- /dev/null +++ b/project/jni/application/quake/source/net_vcr.c @@ -0,0 +1,167 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_vcr.c + +#include "quakedef.h" +#include "net_vcr.h" + +extern int vcrFile; + +// This is the playback portion of the VCR. It reads the file produced +// by the recorder and plays it back to the host. The recording contains +// everything necessary (events, timestamps, and data) to duplicate the game +// from the viewpoint of everything above the network layer. + +static struct +{ + double time; + int op; + long session; +} next; + +int VCR_Init (void) +{ + net_drivers[0].Init = VCR_Init; + + net_drivers[0].SearchForHosts = VCR_SearchForHosts; + net_drivers[0].Connect = VCR_Connect; + net_drivers[0].CheckNewConnections = VCR_CheckNewConnections; + net_drivers[0].QGetMessage = VCR_GetMessage; + net_drivers[0].QSendMessage = VCR_SendMessage; + net_drivers[0].CanSendMessage = VCR_CanSendMessage; + net_drivers[0].Close = VCR_Close; + net_drivers[0].Shutdown = VCR_Shutdown; + + Sys_FileRead(vcrFile, &next, sizeof(next)); + return 0; +} + +void VCR_ReadNext (void) +{ + if (Sys_FileRead(vcrFile, &next, sizeof(next)) == 0) + { + next.op = 255; + Sys_Error ("=== END OF PLAYBACK===\n"); + } + if (next.op < 1 || next.op > VCR_MAX_MESSAGE) + Sys_Error ("VCR_ReadNext: bad op"); +} + + +void VCR_Listen (qboolean state) +{ +} + + +void VCR_Shutdown (void) +{ +} + + +int VCR_GetMessage (qsocket_t *sock) +{ + int ret; + + if (host_time != next.time || next.op != VCR_OP_GETMESSAGE || next.session != *(long *)(&sock->driverdata)) + Sys_Error ("VCR missmatch"); + + Sys_FileRead(vcrFile, &ret, sizeof(int)); + if (ret != 1) + { + VCR_ReadNext (); + return ret; + } + + Sys_FileRead(vcrFile, &net_message.cursize, sizeof(int)); + Sys_FileRead(vcrFile, net_message.data, net_message.cursize); + + VCR_ReadNext (); + + return 1; +} + + +int VCR_SendMessage (qsocket_t *sock, sizebuf_t *data) +{ + int ret; + + if (host_time != next.time || next.op != VCR_OP_SENDMESSAGE || next.session != *(long *)(&sock->driverdata)) + Sys_Error ("VCR missmatch"); + + Sys_FileRead(vcrFile, &ret, sizeof(int)); + + VCR_ReadNext (); + + return ret; +} + + +qboolean VCR_CanSendMessage (qsocket_t *sock) +{ + qboolean ret; + + if (host_time != next.time || next.op != VCR_OP_CANSENDMESSAGE || next.session != *(long *)(&sock->driverdata)) + Sys_Error ("VCR missmatch"); + + Sys_FileRead(vcrFile, &ret, sizeof(int)); + + VCR_ReadNext (); + + return ret; +} + + +void VCR_Close (qsocket_t *sock) +{ +} + + +void VCR_SearchForHosts (qboolean xmit) +{ +} + + +qsocket_t *VCR_Connect (char *host) +{ + return NULL; +} + + +qsocket_t *VCR_CheckNewConnections (void) +{ + qsocket_t *sock; + + if (host_time != next.time || next.op != VCR_OP_CONNECT) + Sys_Error ("VCR missmatch"); + + if (!next.session) + { + VCR_ReadNext (); + return NULL; + } + + sock = NET_NewQSocket (); + *(long *)(&sock->driverdata) = next.session; + + Sys_FileRead (vcrFile, sock->address, NET_NAMELEN); + VCR_ReadNext (); + + return sock; +} diff --git a/project/jni/application/quake/source/net_vcr.h b/project/jni/application/quake/source/net_vcr.h new file mode 100644 index 000000000..237469741 --- /dev/null +++ b/project/jni/application/quake/source/net_vcr.h @@ -0,0 +1,37 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_vcr.h + +#define VCR_OP_CONNECT 1 +#define VCR_OP_GETMESSAGE 2 +#define VCR_OP_SENDMESSAGE 3 +#define VCR_OP_CANSENDMESSAGE 4 +#define VCR_MAX_MESSAGE 4 + +int VCR_Init (void); +void VCR_Listen (qboolean state); +void VCR_SearchForHosts (qboolean xmit); +qsocket_t *VCR_Connect (char *host); +qsocket_t *VCR_CheckNewConnections (void); +int VCR_GetMessage (qsocket_t *sock); +int VCR_SendMessage (qsocket_t *sock, sizebuf_t *data); +qboolean VCR_CanSendMessage (qsocket_t *sock); +void VCR_Close (qsocket_t *sock); +void VCR_Shutdown (void); diff --git a/project/jni/application/quake/source/net_wins.h b/project/jni/application/quake/source/net_wins.h new file mode 100644 index 000000000..1f77d012c --- /dev/null +++ b/project/jni/application/quake/source/net_wins.h @@ -0,0 +1,39 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_wins.h + +int WINS_Init (void); +void WINS_Shutdown (void); +void WINS_Listen (qboolean state); +int WINS_OpenSocket (int port); +int WINS_CloseSocket (int socket); +int WINS_Connect (int socket, struct qsockaddr *addr); +int WINS_CheckNewConnections (void); +int WINS_Read (int socket, byte *buf, int len, struct qsockaddr *addr); +int WINS_Write (int socket, byte *buf, int len, struct qsockaddr *addr); +int WINS_Broadcast (int socket, byte *buf, int len); +char *WINS_AddrToString (struct qsockaddr *addr); +int WINS_StringToAddr (char *string, struct qsockaddr *addr); +int WINS_GetSocketAddr (int socket, struct qsockaddr *addr); +int WINS_GetNameFromAddr (struct qsockaddr *addr, char *name); +int WINS_GetAddrFromName (char *name, struct qsockaddr *addr); +int WINS_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2); +int WINS_GetSocketPort (struct qsockaddr *addr); +int WINS_SetSocketPort (struct qsockaddr *addr, int port); diff --git a/project/jni/application/quake/source/net_wipx.h b/project/jni/application/quake/source/net_wipx.h new file mode 100644 index 000000000..b8adf4161 --- /dev/null +++ b/project/jni/application/quake/source/net_wipx.h @@ -0,0 +1,39 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// net_wipx.h + +int WIPX_Init (void); +void WIPX_Shutdown (void); +void WIPX_Listen (qboolean state); +int WIPX_OpenSocket (int port); +int WIPX_CloseSocket (int socket); +int WIPX_Connect (int socket, struct qsockaddr *addr); +int WIPX_CheckNewConnections (void); +int WIPX_Read (int socket, byte *buf, int len, struct qsockaddr *addr); +int WIPX_Write (int socket, byte *buf, int len, struct qsockaddr *addr); +int WIPX_Broadcast (int socket, byte *buf, int len); +char *WIPX_AddrToString (struct qsockaddr *addr); +int WIPX_StringToAddr (char *string, struct qsockaddr *addr); +int WIPX_GetSocketAddr (int socket, struct qsockaddr *addr); +int WIPX_GetNameFromAddr (struct qsockaddr *addr, char *name); +int WIPX_GetAddrFromName (char *name, struct qsockaddr *addr); +int WIPX_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2); +int WIPX_GetSocketPort (struct qsockaddr *addr); +int WIPX_SetSocketPort (struct qsockaddr *addr, int port); diff --git a/project/jni/application/quake/source/nonintel.c b/project/jni/application/quake/source/nonintel.c new file mode 100644 index 000000000..889e990be --- /dev/null +++ b/project/jni/application/quake/source/nonintel.c @@ -0,0 +1,70 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// nonintel.c: code for non-Intel processors only +// + +#include "quakedef.h" +#include "r_local.h" +#include "d_local.h" + +#if !id386 + +/* +================ +R_Surf8Patch +================ +*/ +void R_Surf8Patch () +{ + // we only patch code on Intel +} + + +/* +================ +R_Surf16Patch +================ +*/ +void R_Surf16Patch () +{ + // we only patch code on Intel +} + + +/* +================ +R_SurfacePatch +================ +*/ +void R_SurfacePatch (void) +{ + // we only patch code on Intel +} + +#ifdef USEFPM +void R_SurfacePatchFPM (void) +{ + // we only patch code on Intel +} +#endif + +#endif // !id386 + diff --git a/project/jni/application/quake/source/pr_cmds.c b/project/jni/application/quake/source/pr_cmds.c new file mode 100644 index 000000000..350694856 --- /dev/null +++ b/project/jni/application/quake/source/pr_cmds.c @@ -0,0 +1,3198 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" + +#define RETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e)) +#ifdef USEFPM +#define RETURN_EDICTFPM(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROGFPM(e)) +#endif +/* +=============================================================================== + + BUILT-IN FUNCTIONS + +=============================================================================== +*/ + +char *PF_VarString (int first) +{ + int i; + static char out[256]; + + out[0] = 0; + for (i=first ; is_name,s); + ed = PROG_TO_EDICT(pr_global_struct->self); + ED_Print (ed); + + Host_Error ("Program error"); +} + +#ifdef USEFPM +void PF_errorFPM (void) +{ + char *s; + edict_FPM_t *ed; + + s = PF_VarString(0); + Con_Printf ("======SERVER ERROR in %s:\n%s\n" + ,pr_strings + pr_xfunction->s_name,s); + ed = PROG_TO_EDICTFPM(pr_global_struct->self); + ED_PrintFPM (ed); + + Host_Error ("Program error"); +} +#endif + +/* +================= +PF_objerror + +Dumps out self, then an error message. The program is aborted and self is +removed, but the level can continue. + +objerror(value) +================= +*/ +void PF_objerror (void) +{ + char *s; + edict_t *ed; + + s = PF_VarString(0); + Con_Printf ("======OBJECT ERROR in %s:\n%s\n" + ,pr_strings + pr_xfunction->s_name,s); + ed = PROG_TO_EDICT(pr_global_struct->self); + ED_Print (ed); + ED_Free (ed); + + Host_Error ("Program error"); +} + +#ifdef USEFPM +void PF_objerrorFPM (void) +{ + char *s; + edict_FPM_t *ed; + + s = PF_VarString(0); + Con_Printf ("======OBJECT ERROR in %s:\n%s\n" + ,pr_strings + pr_xfunction->s_name,s); + ed = PROG_TO_EDICTFPM(pr_global_struct->self); + ED_PrintFPM (ed); + ED_FreeFPM (ed); + + Host_Error ("Program error"); +} +#endif + +/* +============== +PF_makevectors + +Writes new values for v_forward, v_up, and v_right based on angles +makevectors(vector) +============== +*/ +void PF_makevectors (void) +{ + AngleVectors (G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up); +} + +/* +================= +PF_setorigin + +This is the only valid way to move an object without using the physics of the world (setting velocity and waiting). Directly changing origin will not set internal links correctly, so clipping would be messed up. This should be called when an object is spawned, and then only if it is teleported. + +setorigin (entity, origin) +================= +*/ +void PF_setorigin (void) +{ + edict_t *e; + float *org; + + e = G_EDICT(OFS_PARM0); + org = G_VECTOR(OFS_PARM1); + VectorCopy (org, e->v.origin); + SV_LinkEdict (e, false); +} + +#ifdef USEFPM +void PF_setoriginFPM (void) +{ + edict_FPM_t *e; + float *org; + + e = G_EDICTFPM(OFS_PARM0); + org = G_VECTOR(OFS_PARM1); + VectorCopy (org, e->v.origin); + SV_LinkEdictFPM (e, false); +} +#endif + +void SetMinMaxSize (edict_t *e, float *min, float *max, qboolean rotate) +{ + float *angles; + vec3_t rmin, rmax; + float bounds[2][3]; + float xvector[2], yvector[2]; + float a; + vec3_t base, transformed; + int i, j, k, l; + + for (i=0 ; i<3 ; i++) + if (min[i] > max[i]) + PR_RunError ("backwards mins/maxs"); + + rotate = false; // FIXME: implement rotation properly again + + if (!rotate) + { + VectorCopy (min, rmin); + VectorCopy (max, rmax); + } + else + { + // find min / max for rotations + angles = e->v.angles; + + a = (float)(angles[1]/180 * M_PI); + + xvector[0] = (float)cos(a); + xvector[1] = (float)sin(a); + yvector[0] = (float)-sin(a); + yvector[1] = (float)cos(a); + + VectorCopy (min, bounds[0]); + VectorCopy (max, bounds[1]); + + rmin[0] = rmin[1] = rmin[2] = 9999; + rmax[0] = rmax[1] = rmax[2] = -9999; + + for (i=0 ; i<= 1 ; i++) + { + base[0] = bounds[i][0]; + for (j=0 ; j<= 1 ; j++) + { + base[1] = bounds[j][1]; + for (k=0 ; k<= 1 ; k++) + { + base[2] = bounds[k][2]; + + // transform the point + transformed[0] = xvector[0]*base[0] + yvector[0]*base[1]; + transformed[1] = xvector[1]*base[0] + yvector[1]*base[1]; + transformed[2] = base[2]; + + for (l=0 ; l<3 ; l++) + { + if (transformed[l] < rmin[l]) + rmin[l] = transformed[l]; + if (transformed[l] > rmax[l]) + rmax[l] = transformed[l]; + } + } + } + } + } + +// set derived values + VectorCopy (rmin, e->v.mins); + VectorCopy (rmax, e->v.maxs); + VectorSubtract (max, min, e->v.size); + + SV_LinkEdict (e, false); +} + +#ifdef USEFPM +void SetMinMaxSizeFPM (edict_FPM_t *e, float *min, float *max, qboolean rotate) +{ + float *angles; + vec3_t rmin, rmax; + float bounds[2][3]; + float xvector[2], yvector[2]; + float a; + vec3_t base, transformed; + int i, j, k, l; + + for (i=0 ; i<3 ; i++) + if (min[i] > max[i]) + PR_RunError ("backwards mins/maxs"); + + rotate = false; // FIXME: implement rotation properly again + + if (!rotate) + { + VectorCopy (min, rmin); + VectorCopy (max, rmax); + } + else + { + // find min / max for rotations + angles = e->v.angles; + + a = (float)(angles[1]/180 * M_PI); + + xvector[0] = (float)cos(a); + xvector[1] = (float)sin(a); + yvector[0] = (float)-sin(a); + yvector[1] = (float)cos(a); + + VectorCopy (min, bounds[0]); + VectorCopy (max, bounds[1]); + + rmin[0] = rmin[1] = rmin[2] = 9999; + rmax[0] = rmax[1] = rmax[2] = -9999; + + for (i=0 ; i<= 1 ; i++) + { + base[0] = bounds[i][0]; + for (j=0 ; j<= 1 ; j++) + { + base[1] = bounds[j][1]; + for (k=0 ; k<= 1 ; k++) + { + base[2] = bounds[k][2]; + + // transform the point + transformed[0] = xvector[0]*base[0] + yvector[0]*base[1]; + transformed[1] = xvector[1]*base[0] + yvector[1]*base[1]; + transformed[2] = base[2]; + + for (l=0 ; l<3 ; l++) + { + if (transformed[l] < rmin[l]) + rmin[l] = transformed[l]; + if (transformed[l] > rmax[l]) + rmax[l] = transformed[l]; + } + } + } + } + } + +// set derived values + VectorCopy (rmin, e->v.mins); + VectorCopy (rmax, e->v.maxs); + VectorSubtract (max, min, e->v.size); + + SV_LinkEdictFPM (e, false); +} +#endif + +/* +================= +PF_setsize + +the size box is rotated by the current angle + +setsize (entity, minvector, maxvector) +================= +*/ +void PF_setsize (void) +{ + edict_t *e; + float *min, *max; + + e = G_EDICT(OFS_PARM0); + min = G_VECTOR(OFS_PARM1); + max = G_VECTOR(OFS_PARM2); + SetMinMaxSize (e, min, max, false); +} + +#ifdef USEFPM +void PF_setsizeFPM (void) +{ + edict_FPM_t *e; + float *min, *max; + + e = G_EDICTFPM(OFS_PARM0); + min = G_VECTOR(OFS_PARM1); + max = G_VECTOR(OFS_PARM2); + SetMinMaxSizeFPM (e, min, max, false); +} +#endif + +/* +================= +PF_setmodel + +setmodel(entity, model) +================= +*/ +void PF_setmodel (void) +{ + edict_t *e; + char *m, **check; + model_t *mod; + int i; + + e = G_EDICT(OFS_PARM0); + m = G_STRING(OFS_PARM1); + +// check to see if model was properly precached + for (i=0, check = sv.model_precache ; *check ; i++, check++) + if (!strcmp(*check, m)) + break; + + if (!*check) + PR_RunError ("no precache: %s\n", m); + + + e->v.model = m - pr_strings; + e->v.modelindex = (float)i; //SV_ModelIndex (m); + + mod = sv.models[ (int)e->v.modelindex]; // Mod_ForName (m, true); + + if (mod) + SetMinMaxSize (e, mod->mins, mod->maxs, true); + else + SetMinMaxSize (e, vec3_origin, vec3_origin, true); +} + +#ifdef USEFPM +void PF_setmodelFPM (void) +{ + edict_FPM_t *e; + char *m, **check; + model_FPM_t *mod; + int i; + vec3_t mins, maxs; + + e = G_EDICTFPM(OFS_PARM0); + m = G_STRING(OFS_PARM1); + +// check to see if model was properly precached + for (i=0, check = svFPM.model_precache ; *check ; i++, check++) + if (!strcmp(*check, m)) + break; + + if (!*check) + PR_RunError ("no precache: %s\n", m); + + + e->v.model = m - pr_strings; + e->v.modelindex = (float)i; //SV_ModelIndex (m); + + mod = svFPM.models[ (int)e->v.modelindex]; // Mod_ForName (m, true); + + if (mod) { + mins[0]=FPM_TOFLOAT(mod->mins[0]); + mins[1]=FPM_TOFLOAT(mod->mins[1]); + mins[2]=FPM_TOFLOAT(mod->mins[2]); + maxs[0]=FPM_TOFLOAT(mod->maxs[0]); + maxs[1]=FPM_TOFLOAT(mod->maxs[1]); + maxs[2]=FPM_TOFLOAT(mod->maxs[2]); + SetMinMaxSizeFPM (e, mins, maxs, true); + } else { + mins[0]=FPM_TOFLOAT(vec3_originFPM[0]); + mins[1]=FPM_TOFLOAT(vec3_originFPM[1]); + mins[2]=FPM_TOFLOAT(vec3_originFPM[2]); + SetMinMaxSizeFPM (e, mins, mins, true); + } +} +#endif + +/* +================= +PF_bprint + +broadcast print to everyone on server + +bprint(value) +================= +*/ +void PF_bprint (void) +{ + char *s; + + s = PF_VarString(0); + SV_BroadcastPrintf ("%s", s); +} + +/* +================= +PF_sprint + +single print to a specific client + +sprint(clientent, value) +================= +*/ +void PF_sprint (void) +{ + char *s; + client_t *client; + int entnum; + + entnum = G_EDICTNUM(OFS_PARM0); + s = PF_VarString(1); + + if (entnum < 1 || entnum > svs.maxclients) + { + Con_Printf ("tried to sprint to a non-client\n"); + return; + } + + client = &svs.clients[entnum-1]; + + MSG_WriteChar (&client->message,svc_print); + MSG_WriteString (&client->message, s ); +} + +#ifdef USEFPM +void PF_sprintFPM (void) +{ + char *s; + client_FPM_t *client; + int entnum; + + entnum = G_EDICTNUMFPM(OFS_PARM0); + s = PF_VarString(1); + + if (entnum < 1 || entnum > svsFPM.maxclients) + { + Con_Printf ("tried to sprint to a non-client\n"); + return; + } + + client = &svsFPM.clients[entnum-1]; + + MSG_WriteChar (&client->message,svc_print); + MSG_WriteString (&client->message, s ); +} +#endif + +/* +================= +PF_centerprint + +single print to a specific client + +centerprint(clientent, value) +================= +*/ +void PF_centerprint (void) +{ + char *s; + client_t *client; + int entnum; + + entnum = G_EDICTNUM(OFS_PARM0); + s = PF_VarString(1); + + if (entnum < 1 || entnum > svs.maxclients) + { + Con_Printf ("tried to sprint to a non-client\n"); + return; + } + + client = &svs.clients[entnum-1]; + + MSG_WriteChar (&client->message,svc_centerprint); + MSG_WriteString (&client->message, s ); +} + +#ifdef USEFPM +void PF_centerprintFPM (void) +{ + char *s; + client_FPM_t *client; + int entnum; + + entnum = G_EDICTNUMFPM(OFS_PARM0); + s = PF_VarString(1); + + if (entnum < 1 || entnum > svsFPM.maxclients) + { + Con_Printf ("tried to sprint to a non-client\n"); + return; + } + + client = &svsFPM.clients[entnum-1]; + + MSG_WriteChar (&client->message,svc_centerprint); + MSG_WriteString (&client->message, s ); +} +#endif + +/* +================= +PF_normalize + +vector normalize(vector) +================= +*/ +void PF_normalize (void) +{ + float *value1; + vec3_t newvalue; + float new; + + value1 = G_VECTOR(OFS_PARM0); + + new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2]; + new = (float)sqrt(new); + + if (new == 0) + newvalue[0] = newvalue[1] = newvalue[2] = 0; + else + { + new = 1/new; + newvalue[0] = value1[0] * new; + newvalue[1] = value1[1] * new; + newvalue[2] = value1[2] * new; + } + + VectorCopy (newvalue, G_VECTOR(OFS_RETURN)); +} + +/* +================= +PF_vlen + +scalar vlen(vector) +================= +*/ +void PF_vlen (void) +{ + float *value1; + float new; + + value1 = G_VECTOR(OFS_PARM0); + + new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2]; + new = (float)sqrt(new); + + G_FLOAT(OFS_RETURN) = new; +} + +/* +================= +PF_vectoyaw + +float vectoyaw(vector) +================= +*/ +void PF_vectoyaw (void) +{ + float *value1; + float yaw; + + value1 = G_VECTOR(OFS_PARM0); + + if (value1[1] == 0 && value1[0] == 0) + yaw = 0; + else + { + yaw = (float)(int) (atan2(value1[1], value1[0]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + } + + G_FLOAT(OFS_RETURN) = yaw; +} + + +/* +================= +PF_vectoangles + +vector vectoangles(vector) +================= +*/ +void PF_vectoangles (void) +{ + float *value1; + float forward; + float yaw, pitch; + + value1 = G_VECTOR(OFS_PARM0); + + if (value1[1] == 0 && value1[0] == 0) + { + yaw = 0; + if (value1[2] > 0) + pitch = 90; + else + pitch = 270; + } + else + { + yaw = (float)(int) (atan2(value1[1], value1[0]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + + forward = (float)sqrt (value1[0]*value1[0] + value1[1]*value1[1]); + pitch = (float)(int) (atan2(value1[2], forward) * 180 / M_PI); + if (pitch < 0) + pitch += 360; + } + + G_FLOAT(OFS_RETURN+0) = pitch; + G_FLOAT(OFS_RETURN+1) = yaw; + G_FLOAT(OFS_RETURN+2) = 0; +} + +/* +================= +PF_Random + +Returns a number from 0<= num < 1 + +random() +================= +*/ +void PF_random (void) +{ + float num; + + num = (rand ()&0x7fff) / ((float)0x7fff); + + G_FLOAT(OFS_RETURN) = num; +} + +/* +================= +PF_particle + +particle(origin, color, count) +================= +*/ +void PF_particle (void) +{ + float *org, *dir; + float color; + float count; + + org = G_VECTOR(OFS_PARM0); + dir = G_VECTOR(OFS_PARM1); + color = G_FLOAT(OFS_PARM2); + count = G_FLOAT(OFS_PARM3); + SV_StartParticle (org, dir, (int)color, (int)count); +} + +#ifdef USEFPM +void PF_particleFPM (void) +{ + float *org, *dir; + float color; + float count; + vec3_FPM_t orgFPM, dirFPM; + + org = G_VECTOR(OFS_PARM0); + dir = G_VECTOR(OFS_PARM1); + color = G_FLOAT(OFS_PARM2); + count = G_FLOAT(OFS_PARM3); + + orgFPM[0]=FPM_FROMFLOAT(org[0]); + orgFPM[1]=FPM_FROMFLOAT(org[1]); + orgFPM[2]=FPM_FROMFLOAT(org[2]); + dirFPM[0]=FPM_FROMFLOAT(dir[0]); + dirFPM[1]=FPM_FROMFLOAT(dir[1]); + dirFPM[2]=FPM_FROMFLOAT(dir[2]); + SV_StartParticleFPM (orgFPM, dirFPM, (int)color, (int)count); +} +#endif + +/* +================= +PF_ambientsound + +================= +*/ +void PF_ambientsound (void) +{ + char **check; + char *samp; + float *pos; + float vol, attenuation; + int i, soundnum; + + pos = G_VECTOR (OFS_PARM0); + samp = G_STRING(OFS_PARM1); + vol = G_FLOAT(OFS_PARM2); + attenuation = G_FLOAT(OFS_PARM3); + +// check to see if samp was properly precached + for (soundnum=0, check = sv.sound_precache ; *check ; check++, soundnum++) + if (!strcmp(*check,samp)) + break; + + if (!*check) + { + Con_Printf ("no precache: %s\n", samp); + return; + } + +// add an svc_spawnambient command to the level signon packet + + MSG_WriteByte (&sv.signon,svc_spawnstaticsound); + for (i=0 ; i<3 ; i++) + MSG_WriteCoord(&sv.signon, pos[i]); + + MSG_WriteByte (&sv.signon, soundnum); + + MSG_WriteByte (&sv.signon, (int)(vol*255)); + MSG_WriteByte (&sv.signon, (int)(attenuation*64)); + +} + +#ifdef USEFPM +void PF_ambientsoundFPM (void) +{ + char **check; + char *samp; + float *pos; + float vol, attenuation; + int i, soundnum; + + pos = G_VECTOR (OFS_PARM0); + samp = G_STRING(OFS_PARM1); + vol = G_FLOAT(OFS_PARM2); + attenuation = G_FLOAT(OFS_PARM3); + +// check to see if samp was properly precached + for (soundnum=0, check = svFPM.sound_precache ; *check ; check++, soundnum++) + if (!strcmp(*check,samp)) + break; + + if (!*check) + { + Con_Printf ("no precache: %s\n", samp); + return; + } + +// add an svc_spawnambient command to the level signon packet + + MSG_WriteByte (&svFPM.signon,svc_spawnstaticsound); + for (i=0 ; i<3 ; i++) + MSG_WriteCoord(&svFPM.signon, pos[i]); + + MSG_WriteByte (&svFPM.signon, soundnum); + + MSG_WriteByte (&svFPM.signon, (int)(vol*255)); + MSG_WriteByte (&svFPM.signon, (int)(attenuation*64)); +} +#endif + +/* +================= +PF_sound + +Each entity can have eight independant sound sources, like voice, +weapon, feet, etc. + +Channel 0 is an auto-allocate channel, the others override anything +allready running on that entity/channel pair. + +An attenuation of 0 will play full volume everywhere in the level. +Larger attenuations will drop off. + +================= +*/ +void PF_sound (void) +{ + char *sample; + int channel; + edict_t *entity; + int volume; + float attenuation; + + entity = G_EDICT(OFS_PARM0); + channel = (int)G_FLOAT(OFS_PARM1); + sample = G_STRING(OFS_PARM2); + volume = (int)G_FLOAT(OFS_PARM3) * 255; + attenuation = G_FLOAT(OFS_PARM4); + + if (volume < 0 || volume > 255) + Sys_Error ("SV_StartSound: volume = %i", volume); + + if (attenuation < 0 || attenuation > 4) + Sys_Error ("SV_StartSound: attenuation = %f", attenuation); + + if (channel < 0 || channel > 7) + Sys_Error ("SV_StartSound: channel = %i", channel); + + SV_StartSound (entity, channel, sample, volume, attenuation); +} + +#ifdef USEFPM +void PF_soundFPM (void) +{ + char *sample; + int channel; + edict_FPM_t *entity; + int volume; + float attenuation; + + entity = G_EDICTFPM(OFS_PARM0); + channel = (int)G_FLOAT(OFS_PARM1); + sample = G_STRING(OFS_PARM2); + volume = (int)G_FLOAT(OFS_PARM3) * 255; + attenuation = G_FLOAT(OFS_PARM4); + + if (volume < 0 || volume > 255) + Sys_Error ("SV_StartSound: volume = %i", volume); + + if (attenuation < 0 || attenuation > 4) + Sys_Error ("SV_StartSound: attenuation = %f", attenuation); + + if (channel < 0 || channel > 7) + Sys_Error ("SV_StartSound: channel = %i", channel); + + SV_StartSoundFPM (entity, channel, sample, volume, attenuation); +} +#endif + +/* +================= +PF_break + +break() +================= +*/ +void PF_break (void) +{ +Con_Printf ("break statement\n"); +*(int *)-4 = 0; // dump to debugger +// PR_RunError ("break statement"); +} + +/* +================= +PF_traceline + +Used for use tracing and shot targeting +Traces are blocked by bbox and exact bsp entityes, and also slide box entities +if the tryents flag is set. + +traceline (vector1, vector2, tryents) +================= +*/ +void PF_traceline (void) +{ + float *v1, *v2; + trace_t trace; + int nomonsters; + edict_t *ent; + + v1 = G_VECTOR(OFS_PARM0); + v2 = G_VECTOR(OFS_PARM1); + nomonsters = (int)G_FLOAT(OFS_PARM2); + ent = G_EDICT(OFS_PARM3); + + trace = SV_Move (v1, vec3_origin, vec3_origin, v2, nomonsters, ent); + + pr_global_struct->trace_allsolid = (float)trace.allsolid; + pr_global_struct->trace_startsolid = (float)trace.startsolid; + pr_global_struct->trace_fraction = trace.fraction; + pr_global_struct->trace_inwater = (float)trace.inwater; + pr_global_struct->trace_inopen = (float)trace.inopen; + VectorCopy (trace.endpos, pr_global_struct->trace_endpos); + VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal); + pr_global_struct->trace_plane_dist = trace.plane.dist; + if (trace.ent) + pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent); + else + pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts); +} + +#ifdef USEFPM +void PF_tracelineFPM (void) +{ + float *v1, *v2; + trace_FPM_t trace; + int nomonsters; + edict_FPM_t *ent; + vec3_FPM_t v1FPM, v2FPM; + + v1 = G_VECTOR(OFS_PARM0); + v2 = G_VECTOR(OFS_PARM1); + nomonsters = (int)G_FLOAT(OFS_PARM2); + ent = G_EDICTFPM(OFS_PARM3); + + v1FPM[0]=FPM_FROMFLOAT(v1[0]); + v1FPM[1]=FPM_FROMFLOAT(v1[1]); + v1FPM[2]=FPM_FROMFLOAT(v1[2]); + v2FPM[0]=FPM_FROMFLOAT(v2[0]); + v2FPM[1]=FPM_FROMFLOAT(v2[1]); + v2FPM[2]=FPM_FROMFLOAT(v2[2]); + + trace = SV_MoveFPM (v1FPM, vec3_originFPM, vec3_originFPM, v2FPM, nomonsters, ent); + + pr_global_struct->trace_allsolid = (float)trace.allsolid; + pr_global_struct->trace_startsolid = (float)trace.startsolid; + pr_global_struct->trace_fraction = FPM_TOFLOAT(trace.fraction); + pr_global_struct->trace_inwater = (float)trace.inwater; + pr_global_struct->trace_inopen = (float)trace.inopen; + pr_global_struct->trace_endpos[0]=FPM_TOFLOAT(trace.endpos[0]); + pr_global_struct->trace_endpos[1]=FPM_TOFLOAT(trace.endpos[1]); + pr_global_struct->trace_endpos[2]=FPM_TOFLOAT(trace.endpos[2]); + pr_global_struct->trace_plane_normal[0]=FPM_TOFLOAT(trace.plane.normal[0]); + pr_global_struct->trace_plane_normal[1]=FPM_TOFLOAT(trace.plane.normal[1]); + pr_global_struct->trace_plane_normal[2]=FPM_TOFLOAT(trace.plane.normal[2]); + //VectorCopy (trace.endpos, pr_global_struct->trace_endpos); + //VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal); + pr_global_struct->trace_plane_dist = FPM_TOFLOAT(trace.plane.dist); + if (trace.ent) + pr_global_struct->trace_ent = EDICT_TO_PROGFPM(trace.ent); + else + pr_global_struct->trace_ent = EDICT_TO_PROGFPM(svFPM.edicts); +} +#endif + +#ifdef QUAKE2 +extern trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore); + +void PF_TraceToss (void) +{ + trace_t trace; + edict_t *ent; + edict_t *ignore; + + ent = G_EDICT(OFS_PARM0); + ignore = G_EDICT(OFS_PARM1); + + trace = SV_Trace_Toss (ent, ignore); + + pr_global_struct->trace_allsolid = trace.allsolid; + pr_global_struct->trace_startsolid = trace.startsolid; + pr_global_struct->trace_fraction = trace.fraction; + pr_global_struct->trace_inwater = trace.inwater; + pr_global_struct->trace_inopen = trace.inopen; + VectorCopy (trace.endpos, pr_global_struct->trace_endpos); + VectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal); + pr_global_struct->trace_plane_dist = trace.plane.dist; + if (trace.ent) + pr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent); + else + pr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts); +} +#endif + + +/* +================= +PF_checkpos + +Returns true if the given entity can move to the given position from it's +current position by walking or rolling. +FIXME: make work... +scalar checkpos (entity, vector) +================= +*/ +void PF_checkpos (void) +{ +} + +//============================================================================ + +byte checkpvs[MAX_MAP_LEAFS/8]; + +int PF_newcheckclient (int check) +{ + int i; + byte *pvs; + edict_t *ent; + mleaf_t *leaf; + vec3_t org; + +// cycle to the next one + + if (check < 1) + check = 1; + if (check > svs.maxclients) + check = svs.maxclients; + + if (check == svs.maxclients) + i = 1; + else + i = check + 1; + + for ( ; ; i++) + { + if (i == svs.maxclients+1) + i = 1; + + ent = EDICT_NUM(i); + + if (i == check) + break; // didn't find anything else + + if (ent->free) + continue; + if (ent->v.health <= 0) + continue; + if ((int)ent->v.flags & FL_NOTARGET) + continue; + + // anything that is a client, or has a client as an enemy + break; + } + +// get the PVS for the entity + VectorAdd (ent->v.origin, ent->v.view_ofs, org); + leaf = Mod_PointInLeaf (org, sv.worldmodel); + pvs = Mod_LeafPVS (leaf, sv.worldmodel); + Q_memcpy (checkpvs, pvs, (sv.worldmodel->numleafs+7)>>3 ); + + return i; +} + +#ifdef USEFPM +int PF_newcheckclientFPM (int check) +{ + int i; + byte *pvs; + edict_FPM_t *ent; + mleaf_FPM_t *leaf; + vec3_FPM_t org; + vec3_t tmp; + +// cycle to the next one + + if (check < 1) + check = 1; + if (check > svsFPM.maxclients) + check = svsFPM.maxclients; + + if (check == svsFPM.maxclients) + i = 1; + else + i = check + 1; + + for ( ; ; i++) + { + if (i == svsFPM.maxclients+1) + i = 1; + + ent = EDICT_NUMFPM(i); + + if (i == check) + break; // didn't find anything else + + if (ent->free) + continue; + if (ent->v.health <= 0) + continue; + if ((int)ent->v.flags & FL_NOTARGET) + continue; + + // anything that is a client, or has a client as an enemy + break; + } + +// get the PVS for the entity + VectorAdd (ent->v.origin, ent->v.view_ofs, tmp); + VectorToFPM(tmp, org); + leaf = Mod_PointInLeafFPM (org, svFPM.worldmodel); + pvs = Mod_LeafPVSFPM (leaf, svFPM.worldmodel); + Q_memcpy (checkpvs, pvs, (svFPM.worldmodel->numleafs+7)>>3 ); + + return i; +} +#endif + +/* +================= +PF_checkclient + +Returns a client (or object that has a client enemy) that would be a +valid target. + +If there are more than one valid options, they are cycled each frame + +If (self.origin + self.viewofs) is not in the PVS of the current target, +it is not returned at all. + +name checkclient () +================= +*/ +#define MAX_CHECK 16 +int c_invis, c_notvis; +void PF_checkclient (void) +{ + edict_t *ent, *self; + mleaf_t *leaf; + int l; + vec3_t view; + +// find a new check if on a new frame + if (sv.time - sv.lastchecktime >= 0.1) + { + sv.lastcheck = PF_newcheckclient (sv.lastcheck); + sv.lastchecktime = sv.time; + } + +// return check if it might be visible + ent = EDICT_NUM(sv.lastcheck); + if (ent->free || ent->v.health <= 0) + { + RETURN_EDICT(sv.edicts); + return; + } + +// if current entity can't possibly see the check entity, return 0 + self = PROG_TO_EDICT(pr_global_struct->self); + VectorAdd (self->v.origin, self->v.view_ofs, view); + leaf = Mod_PointInLeaf (view, sv.worldmodel); + l = (leaf - sv.worldmodel->leafs) - 1; + if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) ) + { +c_notvis++; + RETURN_EDICT(sv.edicts); + return; + } + +// might be able to see it +c_invis++; + RETURN_EDICT(ent); +} + +#ifdef USEFPM +void PF_checkclientFPM (void) +{ + edict_FPM_t *ent, *self; + mleaf_FPM_t *leaf; + int l; + vec3_FPM_t view; + vec3_t tmp; + +// find a new check if on a new frame + if (svFPM.time - svFPM.lastchecktime >= 0.1) + { + svFPM.lastcheck = PF_newcheckclientFPM (svFPM.lastcheck); + svFPM.lastchecktime = svFPM.time; + } + +// return check if it might be visible + ent = EDICT_NUMFPM(svFPM.lastcheck); + if (ent->free || ent->v.health <= 0) + { + RETURN_EDICTFPM(svFPM.edicts); + return; + } + +// if current entity can't possibly see the check entity, return 0 + self = PROG_TO_EDICTFPM(pr_global_struct->self); + VectorAdd (self->v.origin, self->v.view_ofs, tmp); + VectorToFPM(tmp, view); + leaf = Mod_PointInLeafFPM (view, svFPM.worldmodel); + l = (leaf - svFPM.worldmodel->leafs) - 1; + if ( (l<0) || !(checkpvs[l>>3] & (1<<(l&7)) ) ) + { +c_notvis++; + RETURN_EDICTFPM(svFPM.edicts); + return; + } + +// might be able to see it +c_invis++; + RETURN_EDICTFPM(ent); +} +#endif + +//============================================================================ + + +/* +================= +PF_stuffcmd + +Sends text over to the client's execution buffer + +stuffcmd (clientent, value) +================= +*/ +void PF_stuffcmd (void) +{ + int entnum; + char *str; + client_t *old; + + entnum = G_EDICTNUM(OFS_PARM0); + if (entnum < 1 || entnum > svs.maxclients) + PR_RunError ("Parm 0 not a client"); + str = G_STRING(OFS_PARM1); + + old = host_client; + host_client = &svs.clients[entnum-1]; + Host_ClientCommands ("%s", str); + host_client = old; +} + +#ifdef USEFPM +void PF_stuffcmdFPM (void) +{ + int entnum; + char *str; + client_FPM_t *old; + + entnum = G_EDICTNUMFPM(OFS_PARM0); + if (entnum < 1 || entnum > svsFPM.maxclients) + PR_RunError ("Parm 0 not a client"); + str = G_STRING(OFS_PARM1); + + old = host_clientFPM; + host_clientFPM = &svsFPM.clients[entnum-1]; + Host_ClientCommandsFPM ("%s", str); + host_clientFPM = old; +} +#endif + +/* +================= +PF_localcmd + +Sends text over to the client's execution buffer + +localcmd (string) +================= +*/ +void PF_localcmd (void) +{ + char *str; + + str = G_STRING(OFS_PARM0); + Cbuf_AddText (str); +} + +#ifdef USEFPM +void PF_localcmdFPM (void) +{ + char *str; + + str = G_STRING(OFS_PARM0); + Cbuf_AddText (str); +} +#endif + +/* +================= +PF_cvar + +float cvar (string) +================= +*/ +void PF_cvar (void) +{ + char *str; + + str = G_STRING(OFS_PARM0); + + G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str); +} + +#ifdef USEFPM +void PF_cvarFPM (void) +{ + char *str; + + str = G_STRING(OFS_PARM0); + + G_FLOAT(OFS_RETURN) = Cvar_VariableValue (str); +} +#endif + +/* +================= +PF_cvar_set + +float cvar (string) +================= +*/ +void PF_cvar_set (void) +{ + char *var, *val; + + var = G_STRING(OFS_PARM0); + val = G_STRING(OFS_PARM1); + + Cvar_Set (var, val); +} + +#ifdef USEFPM +void PF_cvar_setFPM (void) +{ + char *var, *val; + + var = G_STRING(OFS_PARM0); + val = G_STRING(OFS_PARM1); + + Cvar_Set (var, val); +} +#endif + +/* +================= +PF_findradius + +Returns a chain of entities that have origins within a spherical area + +findradius (origin, radius) +================= +*/ +void PF_findradius (void) +{ + edict_t *ent, *chain; + float rad; + float *org; + vec3_t eorg; + int i, j; + + chain = (edict_t *)sv.edicts; + + org = G_VECTOR(OFS_PARM0); + rad = G_FLOAT(OFS_PARM1); + + ent = NEXT_EDICT(sv.edicts); + for (i=1 ; ifree) + continue; + if (ent->v.solid == SOLID_NOT) + continue; + for (j=0 ; j<3 ; j++) + eorg[j] = (float)(org[j] - (ent->v.origin[j] + (ent->v.mins[j] + ent->v.maxs[j])*0.5)); + if (Length(eorg) > rad) + continue; + + ent->v.chain = EDICT_TO_PROG(chain); + chain = ent; + } + + RETURN_EDICT(chain); +} + +#ifdef USEFPM +void PF_findradiusFPM (void) +{ + edict_FPM_t *ent, *chain; + float rad; + float *org; + vec3_t eorg; + int i, j; + + chain = (edict_FPM_t *)svFPM.edicts; + + org = G_VECTOR(OFS_PARM0); + rad = G_FLOAT(OFS_PARM1); + + ent = NEXT_EDICTFPM(svFPM.edicts); + for (i=1 ; ifree) + continue; + if (ent->v.solid == SOLID_NOT) + continue; + for (j=0 ; j<3 ; j++) + eorg[j] = (float)(org[j] - (ent->v.origin[j] + (ent->v.mins[j] + ent->v.maxs[j])*0.5)); + if (Length(eorg) > rad) + continue; + + ent->v.chain = EDICT_TO_PROGFPM(chain); + chain = ent; + } + + RETURN_EDICTFPM(chain); +} +#endif + +/* +========= +PF_dprint +========= +*/ +void PF_dprint (void) +{ + Con_DPrintf ("%s",PF_VarString(0)); +} + +#ifdef USEFPM +void PF_dprintFPM (void) +{ + Con_DPrintf ("%s",PF_VarString(0)); +} +#endif + +char pr_string_temp[128]; + +void PF_ftos (void) +{ + float v; + v = G_FLOAT(OFS_PARM0); + + if (v == (int)v) + sprintf (pr_string_temp, "%d",(int)v); + else + sprintf (pr_string_temp, "%5.1f",v); + G_INT(OFS_RETURN) = pr_string_temp - pr_strings; +} + +#ifdef USEFPM +void PF_ftosFPM (void) +{ + float v; + v = G_FLOAT(OFS_PARM0); + + if (v == (int)v) + sprintf (pr_string_temp, "%d",(int)v); + else + sprintf (pr_string_temp, "%5.1f",v); + G_INT(OFS_RETURN) = pr_string_temp - pr_strings; +} +#endif + +void PF_fabs (void) +{ + float v; + v = G_FLOAT(OFS_PARM0); + G_FLOAT(OFS_RETURN) = (float)fabs(v); +} + +#ifdef USEFPM +void PF_fabsFPM (void) +{ + float v; + v = G_FLOAT(OFS_PARM0); + G_FLOAT(OFS_RETURN) = (float)fabs(v); +} +#endif //USEFPM + +void PF_vtos (void) +{ + sprintf (pr_string_temp, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]); + G_INT(OFS_RETURN) = pr_string_temp - pr_strings; +} + +#ifdef USEFPM +void PF_vtosFPM (void) +{ + sprintf (pr_string_temp, "'%5.1f %5.1f %5.1f'", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]); + G_INT(OFS_RETURN) = pr_string_temp - pr_strings; +} +#endif //USEFPM +#ifdef QUAKE2 +void PF_etos (void) +{ + sprintf (pr_string_temp, "entity %i", G_EDICTNUM(OFS_PARM0)); + G_INT(OFS_RETURN) = pr_string_temp - pr_strings; +} + +#ifdef USEFPM +void PF_etosFPM (void) +{ + sprintf (pr_string_temp, "entity %i", G_EDICTNUMFPM(OFS_PARM0)); + G_INT(OFS_RETURN) = pr_string_temp - pr_strings; +} +#endif //USEFPM +#endif + +void PF_Spawn (void) +{ + edict_t *ed; + ed = ED_Alloc(); + RETURN_EDICT(ed); +} + +#ifdef USEFPM +void PF_SpawnFPM (void) +{ + edict_FPM_t *ed; + ed = ED_AllocFPM(); + RETURN_EDICTFPM(ed); +} +#endif //USEFPM + +void PF_Remove (void) +{ + edict_t *ed; + + ed = G_EDICT(OFS_PARM0); + ED_Free (ed); +} + +#ifdef USEFPM +void PF_RemoveFPM (void) +{ + edict_FPM_t *ed; + + ed = G_EDICTFPM(OFS_PARM0); + ED_FreeFPM (ed); +} +#endif //USEFPM + +// entity (entity start, .string field, string match) find = #5; +void PF_Find (void) +#ifdef QUAKE2 +{ + int e; + int f; + char *s, *t; + edict_t *ed; + edict_t *first; + edict_t *second; + edict_t *last; + + first = second = last = (edict_t *)sv.edicts; + e = G_EDICTNUM(OFS_PARM0); + f = G_INT(OFS_PARM1); + s = G_STRING(OFS_PARM2); + if (!s) + PR_RunError ("PF_Find: bad search string"); + + for (e++ ; e < sv.num_edicts ; e++) + { + ed = EDICT_NUM(e); + if (ed->free) + continue; + t = E_STRING(ed,f); + if (!t) + continue; + if (!strcmp(t,s)) + { + if (first == (edict_t *)sv.edicts) + first = ed; + else if (second == (edict_t *)sv.edicts) + second = ed; + ed->v.chain = EDICT_TO_PROG(last); + last = ed; + } + } + + if (first != last) + { + if (last != second) + first->v.chain = last->v.chain; + else + first->v.chain = EDICT_TO_PROG(last); + last->v.chain = EDICT_TO_PROG((edict_t *)sv.edicts); + if (second && second != last) + second->v.chain = EDICT_TO_PROG(last); + } + RETURN_EDICT(first); +} +#else +{ + int e; + int f; + char *s, *t; + edict_t *ed; + + e = G_EDICTNUM(OFS_PARM0); + f = G_INT(OFS_PARM1); + s = G_STRING(OFS_PARM2); + if (!s) + PR_RunError ("PF_Find: bad search string"); + + for (e++ ; e < sv.num_edicts ; e++) + { + ed = EDICT_NUM(e); + if (ed->free) + continue; + t = E_STRING(ed,f); + if (!t) + continue; + if (!strcmp(t,s)) + { + RETURN_EDICT(ed); + return; + } + } + + RETURN_EDICT(sv.edicts); +} +#endif + +#ifdef USEFPM +void PF_FindFPM (void) +#ifdef QUAKE2 +{ + int e; + int f; + char *s, *t; + edict_FPM_t *ed; + edict_FPM_t *first; + edict_FPM_t *second; + edict_FPM_t *last; + + first = second = last = (edict_FPM_t *)svFPM.edicts; + e = G_EDICTNUMFPM(OFS_PARM0); + f = G_INT(OFS_PARM1); + s = G_STRING(OFS_PARM2); + if (!s) + PR_RunError ("PF_Find: bad search string"); + + for (e++ ; e < svFPM.num_edicts ; e++) + { + ed = EDICT_NUMFPM(e); + if (ed->free) + continue; + t = E_STRING(ed,f); + if (!t) + continue; + if (!strcmp(t,s)) + { + if (first == (edict_FPM_t *)svFPM.edicts) + first = ed; + else if (second == (edict_t *)svFPM.edicts) + second = ed; + ed->v.chain = EDICT_TO_PROGFPM(last); + last = ed; + } + } + + if (first != last) + { + if (last != second) + first->v.chain = last->v.chain; + else + first->v.chain = EDICT_TO_PROGFPM(last); + last->v.chain = EDICT_TO_PROGFPM((edict_FPM_t *)svFPM.edicts); + if (second && second != last) + second->v.chain = EDICT_TO_PROGFPM(last); + } + RETURN_EDICTFPM(first); +} +#else +{ + int e; + int f; + char *s, *t; + edict_FPM_t *ed; + + e = G_EDICTNUMFPM(OFS_PARM0); + f = G_INT(OFS_PARM1); + s = G_STRING(OFS_PARM2); + if (!s) + PR_RunError ("PF_Find: bad search string"); + + for (e++ ; e < svFPM.num_edicts ; e++) + { + ed = EDICT_NUMFPM(e); + if (ed->free) + continue; + t = E_STRING(ed,f); + if (!t) + continue; + if (!strcmp(t,s)) + { + RETURN_EDICTFPM(ed); + return; + } + } + + RETURN_EDICTFPM(svFPM.edicts); +} +#endif +#endif //USEFPM + +void PR_CheckEmptyString (char *s) +{ + if (s[0] <= ' ') + PR_RunError ("Bad string"); +} + +#ifdef USEFPM +void PR_CheckEmptyStringFPM (char *s) +{ + if (s[0] <= ' ') + PR_RunError ("Bad string"); +} +#endif //USEFPM + +void PF_precache_file (void) +{ // precache_file is only used to copy files with qcc, it does nothing + G_INT(OFS_RETURN) = G_INT(OFS_PARM0); +} + +#ifdef USEFPM +void PF_precache_fileFPM (void) +{ // precache_file is only used to copy files with qcc, it does nothing + G_INT(OFS_RETURN) = G_INT(OFS_PARM0); +} +#endif //USEFPM + +void PF_precache_sound (void) +{ + char *s; + int i; + + if (sv.state != ss_loading) + PR_RunError ("PF_Precache_*: Precache can only be done in spawn functions"); + + s = G_STRING(OFS_PARM0); + G_INT(OFS_RETURN) = G_INT(OFS_PARM0); + PR_CheckEmptyString (s); + + for (i=0 ; iself); + yaw = G_FLOAT(OFS_PARM0); + dist = G_FLOAT(OFS_PARM1); + + if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) ) + { + G_FLOAT(OFS_RETURN) = 0; + return; + } + + yaw = (float)(yaw*M_PI*2 / 360); + + move[0] = (float)(cos(yaw)*dist); + move[1] = (float)(sin(yaw)*dist); + move[2] = 0; + +// save program state, because SV_movestep may call other progs + oldf = pr_xfunction; + oldself = pr_global_struct->self; + + G_FLOAT(OFS_RETURN) = (float)SV_movestep(ent, move, true); + + +// restore program state + pr_xfunction = oldf; + pr_global_struct->self = oldself; +} + +#ifdef USEFPM +void PF_walkmoveFPM (void) +{ + edict_FPM_t *ent; + fixedpoint_t yaw, dist; + vec3_FPM_t move; + dfunction_t *oldf; + int oldself; + + ent = PROG_TO_EDICTFPM(pr_global_struct->self); + yaw = FPM_FROMFLOAT(G_FLOAT(OFS_PARM0)); + dist = FPM_FROMFLOAT(G_FLOAT(OFS_PARM1)); + + if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) ) + { + G_FLOAT(OFS_RETURN) = 0; + return; + } + + yaw = FPM_MUL(FPM_MUL(yaw,FPM_PI),FPM_FROMLONGC(180)); + + move[0] = FPM_MUL(FPM_COS(yaw),dist); + move[1] = FPM_MUL(FPM_SIN(yaw),dist); + move[2] = 0; + +// save program state, because SV_movestep may call other progs + oldf = pr_xfunction; + oldself = pr_global_struct->self; + + G_FLOAT(OFS_RETURN) = (float)SV_movestepFPM(ent, move, true); + + +// restore program state + pr_xfunction = oldf; + pr_global_struct->self = oldself; +} +#endif //USEFPM + +/* +=============== +PF_droptofloor + +void() droptofloor +=============== +*/ +void PF_droptofloor (void) +{ + edict_t *ent; + vec3_t end; + trace_t trace; + + ent = PROG_TO_EDICT(pr_global_struct->self); + + VectorCopy (ent->v.origin, end); + end[2] -= 256; + + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent); + + if (trace.fraction == 1 || trace.allsolid) + G_FLOAT(OFS_RETURN) = 0; + else + { + VectorCopy (trace.endpos, ent->v.origin); + SV_LinkEdict (ent, false); + ent->v.flags = (float)((int)ent->v.flags | FL_ONGROUND); + ent->v.groundentity = EDICT_TO_PROG(trace.ent); + G_FLOAT(OFS_RETURN) = 1; + } +} + +#ifdef USEFPM +void PF_droptofloorFPM (void) +{ + edict_FPM_t *ent; + vec3_FPM_t end, vmins, vmaxs; + trace_FPM_t trace; + + ent = PROG_TO_EDICTFPM(pr_global_struct->self); + + VectorToFPM(ent->v.origin, end); + //VectorCopy (ent->v.origin, end); + end[2] = FPM_SUB(end[2], FPM_FROMLONGC(256)); + VectorToFPM(ent->v.mins, vmins); + VectorToFPM(ent->v.maxs, vmaxs); + + trace = SV_MoveFPM (end, vmins, vmaxs, end, false, ent); + + if (trace.fraction == 1 || trace.allsolid) + G_FLOAT(OFS_RETURN) = 0; + else + { + FPMToVector(trace.endpos, ent->v.origin); + //VectorCopy (trace.endpos, ent->v.origin); + SV_LinkEdictFPM (ent, false); + ent->v.flags = (float)((int)ent->v.flags | FL_ONGROUND); + ent->v.groundentity = EDICT_TO_PROGFPM(trace.ent); + G_FLOAT(OFS_RETURN) = 1; + } +} +#endif //USEFPM + +/* +=============== +PF_lightstyle + +void(float style, string value) lightstyle +=============== +*/ +void PF_lightstyle (void) +{ + int style; + char *val; + client_t *client; + int j; + + style = (int)G_FLOAT(OFS_PARM0); + val = G_STRING(OFS_PARM1); + +// change the string in sv + sv.lightstyles[style] = val; + +// send message to all clients on this server + if (sv.state != ss_active) + return; + + for (j=0, client = svs.clients ; jactive || client->spawned) + { + MSG_WriteChar (&client->message, svc_lightstyle); + MSG_WriteChar (&client->message,style); + MSG_WriteString (&client->message, val); + } +} + +#ifdef USEFPM +void PF_lightstyleFPM (void) +{ + int style; + char *val; + client_FPM_t *client; + int j; + + style = (int)G_FLOAT(OFS_PARM0); + val = G_STRING(OFS_PARM1); + +// change the string in sv + svFPM.lightstyles[style] = val; + +// send message to all clients on this server + if (svFPM.state != ss_active) + return; + + for (j=0, client = svsFPM.clients ; jactive || client->spawned) + { + MSG_WriteChar (&client->message, svc_lightstyle); + MSG_WriteChar (&client->message,style); + MSG_WriteString (&client->message, val); + } +} +#endif //USEFPM + +void PF_rint (void) +{ + float f; + f = G_FLOAT(OFS_PARM0); + if (f > 0) + G_FLOAT(OFS_RETURN) = (float)(int)(f + 0.5); + else + G_FLOAT(OFS_RETURN) = (float)(int)(f - 0.5); +} +void PF_floor (void) +{ + G_FLOAT(OFS_RETURN) = (float)floor(G_FLOAT(OFS_PARM0)); +} +void PF_ceil (void) +{ + G_FLOAT(OFS_RETURN) = (float)ceil(G_FLOAT(OFS_PARM0)); +} + + +/* +============= +PF_checkbottom +============= +*/ +void PF_checkbottom (void) +{ + edict_t *ent; + + ent = G_EDICT(OFS_PARM0); + + G_FLOAT(OFS_RETURN) = (float)SV_CheckBottom (ent); +} + +#ifdef USEFPM +void PF_checkbottomFPM (void) +{ + edict_FPM_t *ent; + + ent = G_EDICTFPM(OFS_PARM0); + + G_FLOAT(OFS_RETURN) = (float)SV_CheckBottomFPM (ent); +} +#endif //USEFPM + +/* +============= +PF_pointcontents +============= +*/ +void PF_pointcontents (void) +{ + float *v; + + v = G_VECTOR(OFS_PARM0); + + G_FLOAT(OFS_RETURN) = (float)SV_PointContents (v); +} + +#ifdef USEFPM +void PF_pointcontentsFPM (void) +{ + fixedpoint_t v; + + v = FPM_FROMFLOAT(*G_VECTOR(OFS_PARM0)); + + G_FLOAT(OFS_RETURN) = (float)SV_PointContentsFPM (&v); +} +#endif //USEFPM +/* +============= +PF_nextent + +entity nextent(entity) +============= +*/ +void PF_nextent (void) +{ + int i; + edict_t *ent; + + i = G_EDICTNUM(OFS_PARM0); + while (1) + { + i++; + if (i == sv.num_edicts) + { + RETURN_EDICT(sv.edicts); + return; + } + ent = EDICT_NUM(i); + if (!ent->free) + { + RETURN_EDICT(ent); + return; + } + } +} + +#ifdef USEFPM +void PF_nextentFPM (void) +{ + int i; + edict_FPM_t *ent; + + i = G_EDICTNUMFPM(OFS_PARM0); + while (1) + { + i++; + if (i == svFPM.num_edicts) + { + RETURN_EDICTFPM(svFPM.edicts); + return; + } + ent = EDICT_NUMFPM(i); + if (!ent->free) + { + RETURN_EDICTFPM(ent); + return; + } + } +} +#endif //USEFPM + +/* +============= +PF_aim + +Pick a vector for the player to shoot along +vector aim(entity, missilespeed) +============= +*/ +cvar_t sv_aim = {"sv_aim", "0.93"}; +void PF_aim (void) +{ + edict_t *ent, *check, *bestent; + vec3_t start, dir, end, bestdir; + int i, j; + trace_t tr; + float dist, bestdist; + float speed; + + ent = G_EDICT(OFS_PARM0); + speed = G_FLOAT(OFS_PARM1); + + VectorCopy (ent->v.origin, start); + start[2] += 20; + +// try sending a trace straight + VectorCopy (pr_global_struct->v_forward, dir); + VectorMA (start, 2048, dir, end); + tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent); + if (tr.ent && tr.ent->v.takedamage == DAMAGE_AIM + && (!teamplay.value || ent->v.team <=0 || ent->v.team != tr.ent->v.team) ) + { + VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN)); + return; + } + + +// try all possible entities + VectorCopy (dir, bestdir); + bestdist = sv_aim.value; + bestent = NULL; + + check = NEXT_EDICT(sv.edicts); + for (i=1 ; iv.takedamage != DAMAGE_AIM) + continue; + if (check == ent) + continue; + if (teamplay.value && ent->v.team > 0 && ent->v.team == check->v.team) + continue; // don't aim at teammate + for (j=0 ; j<3 ; j++) + end[j] = (float)(check->v.origin[j] + + 0.5*(check->v.mins[j] + check->v.maxs[j])); + VectorSubtract (end, start, dir); + VectorNormalize (dir); + dist = DotProduct (dir, pr_global_struct->v_forward); + if (dist < bestdist) + continue; // to far to turn + tr = SV_Move (start, vec3_origin, vec3_origin, end, false, ent); + if (tr.ent == check) + { // can shoot at this one + bestdist = dist; + bestent = check; + } + } + + if (bestent) + { + VectorSubtract (bestent->v.origin, ent->v.origin, dir); + dist = DotProduct (dir, pr_global_struct->v_forward); + VectorScale (pr_global_struct->v_forward, dist, end); + end[2] = dir[2]; + VectorNormalize (end); + VectorCopy (end, G_VECTOR(OFS_RETURN)); + } + else + { + VectorCopy (bestdir, G_VECTOR(OFS_RETURN)); + } +} + +#ifdef USEFPM +void PF_aimFPM (void) +{ + edict_FPM_t *ent, *check, *bestent; + vec3_FPM_t start, dir, end, bestdir; + vec3_FPM_t vforward, vorigin1, vorigin2; + int i, j; + trace_FPM_t tr; + fixedpoint_t dist, bestdist; + fixedpoint_t speed; + + ent = G_EDICTFPM(OFS_PARM0); + speed = FPM_FROMFLOAT(G_FLOAT(OFS_PARM1)); + + VectorToFPM(ent->v.origin, start); + //VectorCopy (ent->v.origin, start); + start[2] = FPM_ADD(start[2], FPM_FROMLONGC(20)); + +// try sending a trace straight + VectorToFPM(pr_global_struct->v_forward, dir); + //VectorCopy (pr_global_struct->v_forward, dir); + VectorMAFPM (start, FPM_FROMLONG(2048), dir, end); + tr = SV_MoveFPM (start, vec3_originFPM, vec3_originFPM, end, false, ent); + if (tr.ent && tr.ent->v.takedamage == DAMAGE_AIM + && (!teamplay.value || ent->v.team <=0 || ent->v.team != tr.ent->v.team) ) + { + VectorCopy (pr_global_struct->v_forward, G_VECTOR(OFS_RETURN)); + return; + } + + +// try all possible entities + VectorCopy (dir, bestdir); + bestdist = FPM_FROMFLOAT(sv_aim.value); + bestent = NULL; + + VectorToFPM(pr_global_struct->v_forward, vforward); + check = NEXT_EDICTFPM(svFPM.edicts); + for (i=1 ; iv.takedamage != DAMAGE_AIM) + continue; + if (check == ent) + continue; + if (teamplay.value && ent->v.team > 0 && ent->v.team == check->v.team) + continue; // don't aim at teammate + for (j=0 ; j<3 ; j++) + end[j] = FPM_ADD(FPM_FROMFLOATC(check->v.origin[j]), + FPM_MUL(FPM_FROMFLOATC(0.5),FPM_ADD(FPM_FROMFLOAT(check->v.mins[j]), FPM_FROMFLOAT(check->v.maxs[j])))); + VectorSubtractFPM (end, start, dir); + VectorNormalizeFPM (dir); + + dist = DotProductFPM (dir, vforward); + if (dist < bestdist) + continue; // to far to turn + tr = SV_MoveFPM (start, vec3_originFPM, vec3_originFPM, end, false, ent); + if (tr.ent == check) + { // can shoot at this one + bestdist = dist; + bestent = check; + } + } + + if (bestent) + { + VectorToFPM(bestent->v.origin, vorigin1); + VectorToFPM(ent->v.origin, vorigin2); + VectorSubtractFPM (vorigin1, vorigin2, dir); + dist = DotProductFPM (dir, vforward); + VectorScaleFPM (vforward, dist, end); + end[2] = dir[2]; + VectorNormalizeFPM (end); + FPMToVector(end, G_VECTOR(OFS_RETURN)); + //VectorCopy (end, G_VECTOR(OFS_RETURN)); + } + else + { + FPMToVector(bestdir, G_VECTOR(OFS_RETURN)); + //VectorCopy (bestdir, G_VECTOR(OFS_RETURN)); + } +} +#endif //USEFPM + +/* +============== +PF_changeyaw + +This was a major timewaster in progs, so it was converted to C +============== +*/ +void PF_changeyaw (void) +{ + edict_t *ent; + float ideal, current, move, speed; + + ent = PROG_TO_EDICT(pr_global_struct->self); + current = anglemod( ent->v.angles[1] ); + ideal = ent->v.ideal_yaw; + speed = ent->v.yaw_speed; + + if (current == ideal) + return; + move = ideal - current; + if (ideal > current) + { + if (move >= 180) + move = move - 360; + } + else + { + if (move <= -180) + move = move + 360; + } + if (move > 0) + { + if (move > speed) + move = speed; + } + else + { + if (move < -speed) + move = -speed; + } + + ent->v.angles[1] = anglemod (current + move); +} + +#ifdef USEFPM +void PF_changeyawFPM (void) +{ + edict_FPM_t *ent; + fixedpoint_t ideal, current, move, speed; + + ent = PROG_TO_EDICTFPM(pr_global_struct->self); + current = anglemodFPM( FPM_FROMFLOAT(ent->v.angles[1]) ); + ideal = FPM_FROMFLOAT(ent->v.ideal_yaw); + speed = FPM_FROMFLOAT(ent->v.yaw_speed); + + if (current == ideal) + return; + move = ideal - current; + if (ideal > current) + { + if (move >= FPM_FROMLONGC(180)) + move = FPM_SUB(move, FPM_FROMLONGC(360)); + } + else + { + if (move <= FPM_FROMLONGC(-180)) + move = FPM_ADD(move, FPM_FROMLONGC(360)); + } + if (move > 0) + { + if (move > speed) + move = speed; + } + else + { + if (move < -speed) + move = -speed; + } + + ent->v.angles[1] = FPM_TOFLOAT(anglemodFPM (FPM_ADD(current, move))); +} +#endif //USEFPM + +#ifdef QUAKE2 +/* +============== +PF_changepitch +============== +*/ +void PF_changepitch (void) +{ + edict_t *ent; + float ideal, current, move, speed; + + ent = G_EDICT(OFS_PARM0); + current = anglemod( ent->v.angles[0] ); + ideal = ent->v.idealpitch; + speed = ent->v.pitch_speed; + + if (current == ideal) + return; + move = ideal - current; + if (ideal > current) + { + if (move >= 180) + move = move - 360; + } + else + { + if (move <= -180) + move = move + 360; + } + if (move > 0) + { + if (move > speed) + move = speed; + } + else + { + if (move < -speed) + move = -speed; + } + + ent->v.angles[0] = anglemod (current + move); +} +#endif + +/* +=============================================================================== + +MESSAGE WRITING + +=============================================================================== +*/ + +#define MSG_BROADCAST 0 // unreliable to all +#define MSG_ONE 1 // reliable to one (msg_entity) +#define MSG_ALL 2 // reliable to all +#define MSG_INIT 3 // write to the init string + +sizebuf_t *WriteDest (void) +{ + int entnum; + int dest; + edict_t *ent; + + dest = (int)G_FLOAT(OFS_PARM0); + switch (dest) + { + case MSG_BROADCAST: + return &sv.datagram; + + case MSG_ONE: + ent = PROG_TO_EDICT(pr_global_struct->msg_entity); + entnum = NUM_FOR_EDICT(ent); + if (entnum < 1 || entnum > svs.maxclients) + PR_RunError ("WriteDest: not a client"); + return &svs.clients[entnum-1].message; + + case MSG_ALL: + return &sv.reliable_datagram; + + case MSG_INIT: + return &sv.signon; + + default: + PR_RunError ("WriteDest: bad destination"); + break; + } + + return NULL; +} + +#ifdef USEFPM +sizebuf_t *WriteDestFPM (void) +{ + int entnum; + int dest; + edict_FPM_t *ent; + + dest = (int)G_FLOAT(OFS_PARM0); + switch (dest) + { + case MSG_BROADCAST: + return &svFPM.datagram; + + case MSG_ONE: + ent = PROG_TO_EDICTFPM(pr_global_struct->msg_entity); + entnum = NUM_FOR_EDICTFPM(ent); + if (entnum < 1 || entnum > svsFPM.maxclients) + PR_RunError ("WriteDest: not a client"); + return &svsFPM.clients[entnum-1].message; + + case MSG_ALL: + return &svFPM.reliable_datagram; + + case MSG_INIT: + return &svFPM.signon; + + default: + PR_RunError ("WriteDest: bad destination"); + break; + } + + return NULL; +} +#endif //USEFPM + +void PF_WriteByte (void) +{ + MSG_WriteByte (WriteDest(), (int)G_FLOAT(OFS_PARM1)); +} + +void PF_WriteChar (void) +{ + MSG_WriteChar (WriteDest(), (int)G_FLOAT(OFS_PARM1)); +} + +void PF_WriteShort (void) +{ + MSG_WriteShort (WriteDest(), (int)G_FLOAT(OFS_PARM1)); +} + +void PF_WriteLong (void) +{ + MSG_WriteLong (WriteDest(), (int)G_FLOAT(OFS_PARM1)); +} + +void PF_WriteAngle (void) +{ + MSG_WriteAngle (WriteDest(), G_FLOAT(OFS_PARM1)); +} + +void PF_WriteCoord (void) +{ + MSG_WriteCoord (WriteDest(), G_FLOAT(OFS_PARM1)); +} + +void PF_WriteString (void) +{ + MSG_WriteString (WriteDest(), G_STRING(OFS_PARM1)); +} + + +void PF_WriteEntity (void) +{ + MSG_WriteShort (WriteDest(), G_EDICTNUM(OFS_PARM1)); +} + +//============================================================================= + +int SV_ModelIndex (char *name); + +void PF_makestatic (void) +{ + edict_t *ent; + int i; + + ent = G_EDICT(OFS_PARM0); + + MSG_WriteByte (&sv.signon,svc_spawnstatic); + + MSG_WriteByte (&sv.signon, SV_ModelIndex(pr_strings + ent->v.model)); + + MSG_WriteByte (&sv.signon, (int)ent->v.frame); + MSG_WriteByte (&sv.signon, (int)ent->v.colormap); + MSG_WriteByte (&sv.signon, (int)ent->v.skin); + for (i=0 ; i<3 ; i++) + { + MSG_WriteCoord(&sv.signon, ent->v.origin[i]); + MSG_WriteAngle(&sv.signon, ent->v.angles[i]); + } + +// throw the entity away now + ED_Free (ent); +} + +#ifdef USEFPM +void PF_makestaticFPM (void) +{ + edict_FPM_t *ent; + int i; + + ent = G_EDICTFPM(OFS_PARM0); + + MSG_WriteByte (&svFPM.signon,svc_spawnstatic); + + MSG_WriteByte (&svFPM.signon, SV_ModelIndexFPM(pr_strings + ent->v.model)); + + MSG_WriteByte (&svFPM.signon, (int)ent->v.frame); + MSG_WriteByte (&svFPM.signon, (int)ent->v.colormap); + MSG_WriteByte (&svFPM.signon, (int)ent->v.skin); + for (i=0 ; i<3 ; i++) + { + MSG_WriteCoord(&svFPM.signon, ent->v.origin[i]); + MSG_WriteAngle(&svFPM.signon, ent->v.angles[i]); + } + +// throw the entity away now + ED_FreeFPM (ent); +} +#endif //USEFPM + +//============================================================================= + +/* +============== +PF_setspawnparms +============== +*/ +void PF_setspawnparms (void) +{ + edict_t *ent; + int i; + client_t *client; + + ent = G_EDICT(OFS_PARM0); + i = NUM_FOR_EDICT(ent); + if (i < 1 || i > svs.maxclients) + PR_RunError ("Entity is not a client"); + + // copy spawn parms out of the client_t + client = svs.clients + (i-1); + + for (i=0 ; i< NUM_SPAWN_PARMS ; i++) + (&pr_global_struct->parm1)[i] = client->spawn_parms[i]; +} + +#ifdef USEFPM +void PF_setspawnparmsFPM (void) +{ + edict_FPM_t *ent; + int i; + client_FPM_t *client; + + ent = G_EDICTFPM(OFS_PARM0); + i = NUM_FOR_EDICTFPM(ent); + if (i < 1 || i > svsFPM.maxclients) + PR_RunError ("Entity is not a client"); + + // copy spawn parms out of the client_t + client = svsFPM.clients + (i-1); + + for (i=0 ; i< NUM_SPAWN_PARMS ; i++) + (&pr_global_struct->parm1)[i] = client->spawn_parms[i]; +} +#endif //USEFPM + +/* +============== +PF_changelevel +============== +*/ +void PF_changelevel (void) +{ +#ifdef QUAKE2 + char *s1, *s2; + + if (svs.changelevel_issued) + return; + svs.changelevel_issued = true; + + s1 = G_STRING(OFS_PARM0); + s2 = G_STRING(OFS_PARM1); + + if ((int)pr_global_struct->serverflags & (SFL_NEW_UNIT | SFL_NEW_EPISODE)) + Cbuf_AddText (va("changelevel %s %s\n",s1, s2)); + else + Cbuf_AddText (va("changelevel2 %s %s\n",s1, s2)); +#else + char *s; + +// make sure we don't issue two changelevels + if (svs.changelevel_issued) + return; + svs.changelevel_issued = true; + + s = G_STRING(OFS_PARM0); + Cbuf_AddText (va("changelevel %s\n",s)); +#endif +} + +#ifdef USEFPM +void PF_changelevelFPM (void) +{ +#ifdef QUAKE2 + char *s1, *s2; + + if (svsFPM.changelevel_issued) + return; + svsFPM.changelevel_issued = true; + + s1 = G_STRING(OFS_PARM0); + s2 = G_STRING(OFS_PARM1); + + if ((int)pr_global_struct->serverflags & (SFL_NEW_UNIT | SFL_NEW_EPISODE)) + Cbuf_AddText (va("changelevel %s %s\n",s1, s2)); + else + Cbuf_AddText (va("changelevel2 %s %s\n",s1, s2)); +#else + char *s; + +// make sure we don't issue two changelevels + if (svsFPM.changelevel_issued) + return; + svsFPM.changelevel_issued = true; + + s = G_STRING(OFS_PARM0); + Cbuf_AddText (va("changelevel %s\n",s)); +#endif +} +#endif //USEFPM + +#ifdef QUAKE2 + +#define CONTENT_WATER -3 +#define CONTENT_SLIME -4 +#define CONTENT_LAVA -5 + +#define FL_IMMUNE_WATER 131072 +#define FL_IMMUNE_SLIME 262144 +#define FL_IMMUNE_LAVA 524288 + +#define CHAN_VOICE 2 +#define CHAN_BODY 4 + +#define ATTN_NORM 1 + +void PF_WaterMove (void) +{ + edict_t *self; + int flags; + int waterlevel; + int watertype; + float drownlevel; + float damage = 0.0; + + self = PROG_TO_EDICT(pr_global_struct->self); + + if (self->v.movetype == MOVETYPE_NOCLIP) + { + self->v.air_finished = sv.time + 12; + G_FLOAT(OFS_RETURN) = damage; + return; + } + + if (self->v.health < 0) + { + G_FLOAT(OFS_RETURN) = damage; + return; + } + + if (self->v.deadflag == DEAD_NO) + drownlevel = 3; + else + drownlevel = 1; + + flags = (int)self->v.flags; + waterlevel = (int)self->v.waterlevel; + watertype = (int)self->v.watertype; + + if (!(flags & (FL_IMMUNE_WATER + FL_GODMODE))) + if (((flags & FL_SWIM) && (waterlevel < drownlevel)) || (waterlevel >= drownlevel)) + { + if (self->v.air_finished < sv.time) + if (self->v.pain_finished < sv.time) + { + self->v.dmg = self->v.dmg + 2; + if (self->v.dmg > 15) + self->v.dmg = 10; +// T_Damage (self, world, world, self.dmg, 0, FALSE); + damage = self->v.dmg; + self->v.pain_finished = sv.time + 1.0; + } + } + else + { + if (self->v.air_finished < sv.time) +// sound (self, CHAN_VOICE, "player/gasp2.wav", 1, ATTN_NORM); + SV_StartSound (self, CHAN_VOICE, "player/gasp2.wav", 255, ATTN_NORM); + else if (self->v.air_finished < sv.time + 9) +// sound (self, CHAN_VOICE, "player/gasp1.wav", 1, ATTN_NORM); + SV_StartSound (self, CHAN_VOICE, "player/gasp1.wav", 255, ATTN_NORM); + self->v.air_finished = sv.time + 12.0; + self->v.dmg = 2; + } + + if (!waterlevel) + { + if (flags & FL_INWATER) + { + // play leave water sound +// sound (self, CHAN_BODY, "misc/outwater.wav", 1, ATTN_NORM); + SV_StartSound (self, CHAN_BODY, "misc/outwater.wav", 255, ATTN_NORM); + self->v.flags = (float)(flags &~FL_INWATER); + } + self->v.air_finished = sv.time + 12.0; + G_FLOAT(OFS_RETURN) = damage; + return; + } + + if (watertype == CONTENT_LAVA) + { // do damage + if (!(flags & (FL_IMMUNE_LAVA + FL_GODMODE))) + if (self->v.dmgtime < sv.time) + { + if (self->v.radsuit_finished < sv.time) + self->v.dmgtime = sv.time + 0.2; + else + self->v.dmgtime = sv.time + 1.0; +// T_Damage (self, world, world, 10*self.waterlevel, 0, TRUE); + damage = (float)(10*waterlevel); + } + } + else if (watertype == CONTENT_SLIME) + { // do damage + if (!(flags & (FL_IMMUNE_SLIME + FL_GODMODE))) + if (self->v.dmgtime < sv.time && self->v.radsuit_finished < sv.time) + { + self->v.dmgtime = sv.time + 1.0; +// T_Damage (self, world, world, 4*self.waterlevel, 0, TRUE); + damage = (float)(4*waterlevel); + } + } + + if ( !(flags & FL_INWATER) ) + { + +// player enter water sound + if (watertype == CONTENT_LAVA) +// sound (self, CHAN_BODY, "player/inlava.wav", 1, ATTN_NORM); + SV_StartSound (self, CHAN_BODY, "player/inlava.wav", 255, ATTN_NORM); + if (watertype == CONTENT_WATER) +// sound (self, CHAN_BODY, "player/inh2o.wav", 1, ATTN_NORM); + SV_StartSound (self, CHAN_BODY, "player/inh2o.wav", 255, ATTN_NORM); + if (watertype == CONTENT_SLIME) +// sound (self, CHAN_BODY, "player/slimbrn2.wav", 1, ATTN_NORM); + SV_StartSound (self, CHAN_BODY, "player/slimbrn2.wav", 255, ATTN_NORM); + + self->v.flags = (float)(flags | FL_INWATER); + self->v.dmgtime = 0; + } + + if (! (flags & FL_WATERJUMP) ) + { +// self.velocity = self.velocity - 0.8*self.waterlevel*frametime*self.velocity; + VectorMA (self->v.velocity, -0.8 * self->v.waterlevel * host_frametime, self->v.velocity, self->v.velocity); + } + + G_FLOAT(OFS_RETURN) = damage; +} + + +void PF_sin (void) +{ + G_FLOAT(OFS_RETURN) = sin(G_FLOAT(OFS_PARM0)); +} + +void PF_cos (void) +{ + G_FLOAT(OFS_RETURN) = cos(G_FLOAT(OFS_PARM0)); +} + +void PF_sqrt (void) +{ + G_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0)); +} +#endif //QUAKE2 + +void PF_Fixme (void) +{ + PR_RunError ("unimplemented bulitin"); +} + +#ifdef USEFPM +void PF_FixmeFPM (void) +{ + PR_RunError ("unimplemented bulitin"); +} +#endif //USEFPM + +builtin_t pr_builtin[] = +{ +PF_Fixme, +PF_makevectors, // void(entity e) makevectors = #1; +PF_setorigin, // void(entity e, vector o) setorigin = #2; +PF_setmodel, // void(entity e, string m) setmodel = #3; +PF_setsize, // void(entity e, vector min, vector max) setsize = #4; +PF_Fixme, // void(entity e, vector min, vector max) setabssize = #5; +PF_break, // void() break = #6; +PF_random, // float() random = #7; +PF_sound, // void(entity e, float chan, string samp) sound = #8; +PF_normalize, // vector(vector v) normalize = #9; +PF_error, // void(string e) error = #10; +PF_objerror, // void(string e) objerror = #11; +PF_vlen, // float(vector v) vlen = #12; +PF_vectoyaw, // float(vector v) vectoyaw = #13; +PF_Spawn, // entity() spawn = #14; +PF_Remove, // void(entity e) remove = #15; +PF_traceline, // float(vector v1, vector v2, float tryents) traceline = #16; +PF_checkclient, // entity() clientlist = #17; +PF_Find, // entity(entity start, .string fld, string match) find = #18; +PF_precache_sound, // void(string s) precache_sound = #19; +PF_precache_model, // void(string s) precache_model = #20; +PF_stuffcmd, // void(entity client, string s)stuffcmd = #21; +PF_findradius, // entity(vector org, float rad) findradius = #22; +PF_bprint, // void(string s) bprint = #23; +PF_sprint, // void(entity client, string s) sprint = #24; +PF_dprint, // void(string s) dprint = #25; +PF_ftos, // void(string s) ftos = #26; +PF_vtos, // void(string s) vtos = #27; +PF_coredump, +PF_traceon, +PF_traceoff, +PF_eprint, // void(entity e) debug print an entire entity +PF_walkmove, // float(float yaw, float dist) walkmove +PF_Fixme, // float(float yaw, float dist) walkmove +PF_droptofloor, +PF_lightstyle, +PF_rint, +PF_floor, +PF_ceil, +PF_Fixme, +PF_checkbottom, +PF_pointcontents, +PF_Fixme, +PF_fabs, +PF_aim, +PF_cvar, +PF_localcmd, +PF_nextent, +PF_particle, +PF_changeyaw, +PF_Fixme, +PF_vectoangles, + +PF_WriteByte, +PF_WriteChar, +PF_WriteShort, +PF_WriteLong, +PF_WriteCoord, +PF_WriteAngle, +PF_WriteString, +PF_WriteEntity, + +#ifdef QUAKE2 +PF_sin, +PF_cos, +PF_sqrt, +PF_changepitch, +PF_TraceToss, +PF_etos, +PF_WaterMove, +#else +PF_Fixme, +PF_Fixme, +PF_Fixme, +PF_Fixme, +PF_Fixme, +PF_Fixme, +PF_Fixme, +#endif + +SV_MoveToGoal, +PF_precache_file, +PF_makestatic, + +PF_changelevel, +PF_Fixme, + +PF_cvar_set, +PF_centerprint, + +PF_ambientsound, + +PF_precache_model, +PF_precache_sound, // precache_sound2 is different only for qcc +PF_precache_file, + +PF_setspawnparms +}; + +#ifdef USEFPM +builtin_t pr_builtinFPM[] = +{ +PF_FixmeFPM, +PF_makevectors, // void(entity e) makevectors = #1; +PF_setoriginFPM, // void(entity e, vector o) setorigin = #2; +PF_setmodelFPM, // void(entity e, string m) setmodel = #3; +PF_setsizeFPM, // void(entity e, vector min, vector max) setsize = #4; +PF_FixmeFPM, // void(entity e, vector min, vector max) setabssize = #5; +PF_break, // void() break = #6; +PF_random, // float() random = #7; +PF_soundFPM, // void(entity e, float chan, string samp) sound = #8; +PF_normalize, // vector(vector v) normalize = #9; +PF_errorFPM, // void(string e) error = #10; +PF_objerrorFPM, // void(string e) objerror = #11; +PF_vlen, // float(vector v) vlen = #12; +PF_vectoyaw, // float(vector v) vectoyaw = #13; +PF_SpawnFPM, // entity() spawn = #14; +PF_RemoveFPM, // void(entity e) remove = #15; +PF_tracelineFPM, // float(vector v1, vector v2, float tryents) traceline = #16; +PF_checkclientFPM, // entity() clientlist = #17; +PF_FindFPM, // entity(entity start, .string fld, string match) find = #18; +PF_precache_soundFPM, // void(string s) precache_sound = #19; +PF_precache_modelFPM, // void(string s) precache_model = #20; +PF_stuffcmdFPM, // void(entity client, string s)stuffcmd = #21; +PF_findradiusFPM, // entity(vector org, float rad) findradius = #22; +PF_bprint, // void(string s) bprint = #23; +PF_sprintFPM, // void(entity client, string s) sprint = #24; +PF_dprintFPM, // void(string s) dprint = #25; +PF_ftosFPM, // void(string s) ftos = #26; +PF_vtosFPM, // void(string s) vtos = #27; +PF_coredumpFPM, +PF_traceonFPM, +PF_traceoffFPM, +PF_eprintFPM, // void(entity e) debug print an entire entity +PF_walkmoveFPM, // float(float yaw, float dist) walkmove +PF_FixmeFPM, // float(float yaw, float dist) walkmove +PF_droptofloorFPM, +PF_lightstyleFPM, +PF_rint, +PF_floor, +PF_ceil, +PF_FixmeFPM, +PF_checkbottomFPM, +PF_pointcontentsFPM, +PF_FixmeFPM, +PF_fabsFPM, +PF_aimFPM, +PF_cvarFPM, +PF_localcmdFPM, +PF_nextentFPM, +PF_particleFPM, +PF_changeyawFPM, +PF_FixmeFPM, +PF_vectoangles, + +PF_WriteByte, +PF_WriteChar, +PF_WriteShort, +PF_WriteLong, +PF_WriteCoord, +PF_WriteAngle, +PF_WriteString, +PF_WriteEntity, + +#ifdef QUAKE2 +PF_sin, +PF_cos, +PF_sqrt, +PF_changepitchFPM, +PF_TraceTossFPM, +PF_etosFPM, +PF_WaterMoveFPM, +#else +PF_FixmeFPM, +PF_FixmeFPM, +PF_FixmeFPM, +PF_FixmeFPM, +PF_FixmeFPM, +PF_FixmeFPM, +PF_FixmeFPM, +#endif + +SV_MoveToGoalFPM, +PF_precache_fileFPM, +PF_makestaticFPM, + +PF_changelevelFPM, +PF_FixmeFPM, + +PF_cvar_setFPM, +PF_centerprintFPM, + +PF_ambientsoundFPM, + +PF_precache_modelFPM, +PF_precache_soundFPM, // precache_sound2 is different only for qcc +PF_precache_fileFPM, + +PF_setspawnparms +}; +#endif + +builtin_t *pr_builtins = pr_builtin; +int pr_numbuiltins = sizeof(pr_builtin)/sizeof(pr_builtin[0]); + +#ifdef USEFPM +builtin_t *pr_builtinsFPM = pr_builtinFPM; +int pr_numbuiltinsFPM = sizeof(pr_builtinFPM)/sizeof(pr_builtinFPM[0]); +#endif diff --git a/project/jni/application/quake/source/pr_comp.h b/project/jni/application/quake/source/pr_comp.h new file mode 100644 index 000000000..fb0925161 --- /dev/null +++ b/project/jni/application/quake/source/pr_comp.h @@ -0,0 +1,180 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// this file is shared by quake and qcc + +typedef int func_t; +typedef int string_t; + +typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer} etype_t; + + +#define OFS_NULL 0 +#define OFS_RETURN 1 +#define OFS_PARM0 4 // leave 3 ofs for each parm to hold vectors +#define OFS_PARM1 7 +#define OFS_PARM2 10 +#define OFS_PARM3 13 +#define OFS_PARM4 16 +#define OFS_PARM5 19 +#define OFS_PARM6 22 +#define OFS_PARM7 25 +#define RESERVED_OFS 28 + + +enum { + OP_DONE, + OP_MUL_F, + OP_MUL_V, + OP_MUL_FV, + OP_MUL_VF, + OP_DIV_F, + OP_ADD_F, + OP_ADD_V, + OP_SUB_F, + OP_SUB_V, + + OP_EQ_F, + OP_EQ_V, + OP_EQ_S, + OP_EQ_E, + OP_EQ_FNC, + + OP_NE_F, + OP_NE_V, + OP_NE_S, + OP_NE_E, + OP_NE_FNC, + + OP_LE, + OP_GE, + OP_LT, + OP_GT, + + OP_LOAD_F, + OP_LOAD_V, + OP_LOAD_S, + OP_LOAD_ENT, + OP_LOAD_FLD, + OP_LOAD_FNC, + + OP_ADDRESS, + + OP_STORE_F, + OP_STORE_V, + OP_STORE_S, + OP_STORE_ENT, + OP_STORE_FLD, + OP_STORE_FNC, + + OP_STOREP_F, + OP_STOREP_V, + OP_STOREP_S, + OP_STOREP_ENT, + OP_STOREP_FLD, + OP_STOREP_FNC, + + OP_RETURN, + OP_NOT_F, + OP_NOT_V, + OP_NOT_S, + OP_NOT_ENT, + OP_NOT_FNC, + OP_IF, + OP_IFNOT, + OP_CALL0, + OP_CALL1, + OP_CALL2, + OP_CALL3, + OP_CALL4, + OP_CALL5, + OP_CALL6, + OP_CALL7, + OP_CALL8, + OP_STATE, + OP_GOTO, + OP_AND, + OP_OR, + + OP_BITAND, + OP_BITOR +}; + + +typedef struct statement_s +{ + unsigned short op; + short a,b,c; +} dstatement_t; + +typedef struct +{ + unsigned short type; // if DEF_SAVEGLOBGAL bit is set + // the variable needs to be saved in savegames + unsigned short ofs; + int s_name; +} ddef_t; +#define DEF_SAVEGLOBAL (1<<15) + +#define MAX_PARMS 8 + +typedef struct +{ + int first_statement; // negative numbers are builtins + int parm_start; + int locals; // total ints of parms + locals + + int profile; // runtime + + int s_name; + int s_file; // source file defined in + + int numparms; + byte parm_size[MAX_PARMS]; +} dfunction_t; + + +#define PROG_VERSION 6 +typedef struct +{ + int version; + int crc; // check of header file + + int ofs_statements; + int numstatements; // statement 0 is an error + + int ofs_globaldefs; + int numglobaldefs; + + int ofs_fielddefs; + int numfielddefs; + + int ofs_functions; + int numfunctions; // function 0 is an empty + + int ofs_strings; + int numstrings; // first string is a null string + + int ofs_globals; + int numglobals; + + int entityfields; +} dprograms_t; + diff --git a/project/jni/application/quake/source/pr_edict.c b/project/jni/application/quake/source/pr_edict.c new file mode 100644 index 000000000..66d20e23b --- /dev/null +++ b/project/jni/application/quake/source/pr_edict.c @@ -0,0 +1,1567 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sv_edict.c -- entity dictionary + +#include "quakedef.h" + +dprograms_t *progs; +dfunction_t *pr_functions; +char *pr_strings; +ddef_t *pr_fielddefs; +ddef_t *pr_globaldefs; +dstatement_t *pr_statements; +globalvars_t *pr_global_struct; +float *pr_globals; // same as pr_global_struct +int pr_edict_size; // in bytes + +unsigned short pr_crc; + +int type_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4}; + +ddef_t *ED_FieldAtOfs (int ofs); +qboolean ED_ParseEpair (void *base, ddef_t *key, char *s); + +cvar_t nomonsters = {"nomonsters", "0"}; +cvar_t gamecfg = {"gamecfg", "0"}; +cvar_t scratch1 = {"scratch1", "0"}; +cvar_t scratch2 = {"scratch2", "0"}; +cvar_t scratch3 = {"scratch3", "0"}; +cvar_t scratch4 = {"scratch4", "0"}; +cvar_t savedgamecfg = {"savedgamecfg", "0", true}; +cvar_t saved1 = {"saved1", "0", true}; +cvar_t saved2 = {"saved2", "0", true}; +cvar_t saved3 = {"saved3", "0", true}; +cvar_t saved4 = {"saved4", "0", true}; + +#define MAX_FIELD_LEN 64 +#define GEFV_CACHESIZE 2 + +typedef struct { + ddef_t *pcache; + char field[MAX_FIELD_LEN]; +} gefv_cache; + +static gefv_cache gefvCache[GEFV_CACHESIZE] = {{NULL, ""}, {NULL, ""}}; + +/* +================= +ED_ClearEdict + +Sets everything to NULL +================= +*/ +void ED_ClearEdict (edict_t *e) +{ + Q_memset (&e->v, 0, progs->entityfields * 4); + e->free = false; +} + +#ifdef USEFPM +void ED_ClearEdictFPM (edict_FPM_t *e) +{ + Q_memset (&e->v, 0, progs->entityfields * 4); + e->free = false; +} +#endif //USEFPM + +/* +================= +ED_Alloc + +Either finds a free edict, or allocates a new one. +Try to avoid reusing an entity that was recently freed, because it +can cause the client to think the entity morphed into something else +instead of being removed and recreated, which can cause interpolated +angles and bad trails. +================= +*/ +edict_t *ED_Alloc (void) +{ + int i; + edict_t *e; + + for ( i=svs.maxclients+1 ; ifree && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) ) + { + ED_ClearEdict (e); + return e; + } + } + + if (i == MAX_EDICTS) + Sys_Error ("ED_Alloc: no free edicts"); + + sv.num_edicts++; + e = EDICT_NUM(i); + ED_ClearEdict (e); + + return e; +} + +#ifdef USEFPM +edict_FPM_t *ED_AllocFPM (void) +{ + int i; + edict_FPM_t *e; + + for ( i=svsFPM.maxclients+1 ; ifree && ( e->freetime < 2 || svFPM.time - e->freetime > 0.5 ) ) + { + ED_ClearEdictFPM (e); + return e; + } + } + + if (i == MAX_EDICTS) + Sys_Error ("ED_Alloc: no free edicts"); + + svFPM.num_edicts++; + e = EDICT_NUMFPM(i); + ED_ClearEdictFPM (e); + + return e; +} +#endif //USEFPM + +/* +================= +ED_Free + +Marks the edict as free +FIXME: walk all entities and NULL out references to this entity +================= +*/ +void ED_Free (edict_t *ed) +{ + SV_UnlinkEdict (ed); // unlink from world bsp + + ed->free = true; + ed->v.model = 0; + ed->v.takedamage = 0; + ed->v.modelindex = 0; + ed->v.colormap = 0; + ed->v.skin = 0; + ed->v.frame = 0; + VectorCopy (vec3_origin, ed->v.origin); + VectorCopy (vec3_origin, ed->v.angles); + ed->v.nextthink = -1; + ed->v.solid = 0; + + ed->freetime = (float)sv.time; +} + +#ifdef USEFPM +void ED_FreeFPM (edict_FPM_t *ed) +{ + SV_UnlinkEdictFPM (ed); // unlink from world bsp + + ed->free = true; + ed->v.model = 0; + ed->v.takedamage = 0; + ed->v.modelindex = 0; + ed->v.colormap = 0; + ed->v.skin = 0; + ed->v.frame = 0; + ed->v.origin[0]=FPM_TOFLOAT(vec3_originFPM[0]); + ed->v.origin[1]=FPM_TOFLOAT(vec3_originFPM[1]); + ed->v.origin[2]=FPM_TOFLOAT(vec3_originFPM[2]); + ed->v.angles[0]=ed->v.origin[0]; + ed->v.angles[1]=ed->v.origin[1]; + ed->v.angles[2]=ed->v.origin[2]; + //VectorCopy (vec3_originFPM, ed->v.origin); + //VectorCopy (vec3_originFPM, ed->v.angles); + ed->v.nextthink = -1; + ed->v.solid = 0; + + ed->freetime = (float)svFPM.time; +} +#endif //USEFPM + +//=========================================================================== + +/* +============ +ED_GlobalAtOfs +============ +*/ +ddef_t *ED_GlobalAtOfs (int ofs) +{ + ddef_t *def; + int i; + + for (i=0 ; inumglobaldefs ; i++) + { + def = &pr_globaldefs[i]; + if (def->ofs == ofs) + return def; + } + return NULL; +} + +/* +============ +ED_FieldAtOfs +============ +*/ +ddef_t *ED_FieldAtOfs (int ofs) +{ + ddef_t *def; + int i; + + for (i=0 ; inumfielddefs ; i++) + { + def = &pr_fielddefs[i]; + if (def->ofs == ofs) + return def; + } + return NULL; +} + +/* +============ +ED_FindField +============ +*/ +ddef_t *ED_FindField (char *name) +{ + ddef_t *def; + int i; + + for (i=0 ; inumfielddefs ; i++) + { + def = &pr_fielddefs[i]; + if (!strcmp(pr_strings + def->s_name,name) ) + return def; + } + return NULL; +} + + +/* +============ +ED_FindGlobal +============ +*/ +ddef_t *ED_FindGlobal (char *name) +{ + ddef_t *def; + int i; + + for (i=0 ; inumglobaldefs ; i++) + { + def = &pr_globaldefs[i]; + if (!strcmp(pr_strings + def->s_name,name) ) + return def; + } + return NULL; +} + + +/* +============ +ED_FindFunction +============ +*/ +dfunction_t *ED_FindFunction (char *name) +{ + dfunction_t *func; + int i; + + for (i=0 ; inumfunctions ; i++) + { + func = &pr_functions[i]; + if (!strcmp(pr_strings + func->s_name,name) ) + return func; + } + return NULL; +} + + +eval_t *GetEdictFieldValue(edict_t *ed, char *field) +{ + ddef_t *def = NULL; + int i; + static int rep = 0; + + for (i=0 ; iv + def->ofs*4); +} + +#ifdef USEFPM +eval_t *GetEdictFieldValueFPM(edict_FPM_t *ed, char *field) +{ + ddef_t *def = NULL; + int i; + static int rep = 0; + + for (i=0 ; iv + def->ofs*4); +} +#endif //USEFPM + +/* +============ +PR_ValueString + +Returns a string describing *data in a type specific manner +============= +*/ +char *PR_ValueString (etype_t type, eval_t *val) +{ + static char line[256]; + ddef_t *def; + dfunction_t *f; + + type &= ~DEF_SAVEGLOBAL; + + switch (type) + { + case ev_string: + sprintf (line, "%s", pr_strings + val->string); + break; + case ev_entity: + sprintf (line, "entity %i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)) ); + break; + case ev_function: + f = pr_functions + val->function; + sprintf (line, "%s()", pr_strings + f->s_name); + break; + case ev_field: + def = ED_FieldAtOfs ( val->_int ); + sprintf (line, ".%s", pr_strings + def->s_name); + break; + case ev_void: + sprintf (line, "void"); + break; + case ev_float: + sprintf (line, "%5.1f", val->_float); + break; + case ev_vector: + sprintf (line, "'%5.1f %5.1f %5.1f'", val->vector[0], val->vector[1], val->vector[2]); + break; + case ev_pointer: + sprintf (line, "pointer"); + break; + default: + sprintf (line, "bad type %i", type); + break; + } + + return line; +} + +/* +============ +PR_UglyValueString + +Returns a string describing *data in a type specific manner +Easier to parse than PR_ValueString +============= +*/ +char *PR_UglyValueString (etype_t type, eval_t *val) +{ + static char line[256]; + ddef_t *def; + dfunction_t *f; + + type &= ~DEF_SAVEGLOBAL; + + switch (type) + { + case ev_string: + sprintf (line, "%s", pr_strings + val->string); + break; + case ev_entity: + sprintf (line, "%i", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict))); + break; + case ev_function: + f = pr_functions + val->function; + sprintf (line, "%s", pr_strings + f->s_name); + break; + case ev_field: + def = ED_FieldAtOfs ( val->_int ); + sprintf (line, "%s", pr_strings + def->s_name); + break; + case ev_void: + sprintf (line, "void"); + break; + case ev_float: + sprintf (line, "%f", val->_float); + break; + case ev_vector: + sprintf (line, "%f %f %f", val->vector[0], val->vector[1], val->vector[2]); + break; + default: + sprintf (line, "bad type %i", type); + break; + } + + return line; +} + +/* +============ +PR_GlobalString + +Returns a string with a description and the contents of a global, +padded to 20 field width +============ +*/ +char *PR_GlobalString (int ofs) +{ + char *s; + int i; + ddef_t *def; + void *val; + static char line[128]; + + val = (void *)&pr_globals[ofs]; + def = ED_GlobalAtOfs(ofs); + if (!def) + sprintf (line,"%i(???)", ofs); + else + { + s = PR_ValueString (def->type, val); + sprintf (line,"%i(%s)%s", ofs, pr_strings + def->s_name, s); + } + + i = strlen(line); + for ( ; i<20 ; i++) + strcat (line," "); + strcat (line," "); + + return line; +} + +char *PR_GlobalStringNoContents (int ofs) +{ + int i; + ddef_t *def; + static char line[128]; + + def = ED_GlobalAtOfs(ofs); + if (!def) + sprintf (line,"%i(???)", ofs); + else + sprintf (line,"%i(%s)", ofs, pr_strings + def->s_name); + + i = strlen(line); + for ( ; i<20 ; i++) + strcat (line," "); + strcat (line," "); + + return line; +} + + +/* +============= +ED_Print + +For debugging +============= +*/ +void ED_Print (edict_t *ed) +{ + int l; + ddef_t *d; + int *v; + int i, j; + char *name; + int type; + + if (ed->free) + { + Con_Printf ("FREE\n"); + return; + } + + Con_Printf("\nEDICT %i:\n", NUM_FOR_EDICT(ed)); + for (i=1 ; inumfielddefs ; i++) + { + d = &pr_fielddefs[i]; + name = pr_strings + d->s_name; + if (name[strlen(name)-2] == '_') + continue; // skip _x, _y, _z vars + + v = (int *)((char *)&ed->v + d->ofs*4); + + // if the value is still all 0, skip the field + type = d->type & ~DEF_SAVEGLOBAL; + + for (j=0 ; jtype, (eval_t *)v)); + } +} + +#ifdef USEFPM +void ED_PrintFPM (edict_FPM_t *ed) +{ + int l; + ddef_t *d; + int *v; + int i, j; + char *name; + int type; + + if (ed->free) + { + Con_Printf ("FREE\n"); + return; + } + + Con_Printf("\nEDICT %i:\n", NUM_FOR_EDICTFPM(ed)); + for (i=1 ; inumfielddefs ; i++) + { + d = &pr_fielddefs[i]; + name = pr_strings + d->s_name; + if (name[strlen(name)-2] == '_') + continue; // skip _x, _y, _z vars + + v = (int *)((char *)&ed->v + d->ofs*4); + + // if the value is still all 0, skip the field + type = d->type & ~DEF_SAVEGLOBAL; + + for (j=0 ; jtype, (eval_t *)v)); + } +} +#endif //USEFPM + +/* +============= +ED_Write + +For savegames +============= +*/ +void ED_Write (FILE *f, edict_t *ed) +{ + ddef_t *d; + int *v; + int i, j; + char *name; + int type; + + fprintf (f, "{\n"); + + if (ed->free) + { + fprintf (f, "}\n"); + return; + } + + for (i=1 ; inumfielddefs ; i++) + { + d = &pr_fielddefs[i]; + name = pr_strings + d->s_name; + if (name[strlen(name)-2] == '_') + continue; // skip _x, _y, _z vars + + v = (int *)((char *)&ed->v + d->ofs*4); + + // if the value is still all 0, skip the field + type = d->type & ~DEF_SAVEGLOBAL; + for (j=0 ; jtype, (eval_t *)v)); + } + + fprintf (f, "}\n"); +} + +#ifdef USEFPM +void ED_WriteFPM (FILE *f, edict_FPM_t *ed) +{ + ddef_t *d; + int *v; + int i, j; + char *name; + int type; + + fprintf (f, "{\n"); + + if (ed->free) + { + fprintf (f, "}\n"); + return; + } + + for (i=1 ; inumfielddefs ; i++) + { + d = &pr_fielddefs[i]; + name = pr_strings + d->s_name; + if (name[strlen(name)-2] == '_') + continue; // skip _x, _y, _z vars + + v = (int *)((char *)&ed->v + d->ofs*4); + + // if the value is still all 0, skip the field + type = d->type & ~DEF_SAVEGLOBAL; + for (j=0 ; jtype, (eval_t *)v)); + } + + fprintf (f, "}\n"); +} +#endif //USEFPM + +void ED_PrintNum (int ent) +{ + ED_Print (EDICT_NUM(ent)); +} + +/* +============= +ED_PrintEdicts + +For debugging, prints all the entities in the current server +============= +*/ +void ED_PrintEdicts (void) +{ + int i; + + Con_Printf ("%i entities\n", sv.num_edicts); + for (i=0 ; i= sv.num_edicts) + { + Con_Printf("Bad edict number\n"); + return; + } + ED_PrintNum (i); +} + +/* +============= +ED_Count + +For debugging +============= +*/ +void ED_Count (void) +{ + int i; + edict_t *ent; + int active, models, solid, step; + + active = models = solid = step = 0; + for (i=0 ; ifree) + continue; + active++; + if (ent->v.solid) + solid++; + if (ent->v.model) + models++; + if (ent->v.movetype == MOVETYPE_STEP) + step++; + } + + Con_Printf ("num_edicts:%3i\n", sv.num_edicts); + Con_Printf ("active :%3i\n", active); + Con_Printf ("view :%3i\n", models); + Con_Printf ("touch :%3i\n", solid); + Con_Printf ("step :%3i\n", step); + +} + +/* +============================================================================== + + ARCHIVING GLOBALS + +FIXME: need to tag constants, doesn't really work +============================================================================== +*/ + +/* +============= +ED_WriteGlobals +============= +*/ +void ED_WriteGlobals (FILE *f) +{ + ddef_t *def; + int i; + char *name; + int type; + + fprintf (f,"{\n"); + for (i=0 ; inumglobaldefs ; i++) + { + def = &pr_globaldefs[i]; + type = def->type; + if ( !(def->type & DEF_SAVEGLOBAL) ) + continue; + type &= ~DEF_SAVEGLOBAL; + + if (type != ev_string + && type != ev_float + && type != ev_entity) + continue; + + name = pr_strings + def->s_name; + fprintf (f,"\"%s\" ", name); + fprintf (f,"\"%s\"\n", PR_UglyValueString(type, (eval_t *)&pr_globals[def->ofs])); + } + fprintf (f,"}\n"); +} + +/* +============= +ED_ParseGlobals +============= +*/ +void ED_ParseGlobals (char *data) +{ + char keyname[64]; + ddef_t *key; + + while (1) + { + // parse key + data = COM_Parse (data); + if (com_token[0] == '}') + break; + if (!data) + Sys_Error ("ED_ParseEntity: EOF without closing brace"); + + strcpy (keyname, com_token); + + // parse value + data = COM_Parse (data); + if (!data) + Sys_Error ("ED_ParseEntity: EOF without closing brace"); + + if (com_token[0] == '}') + Sys_Error ("ED_ParseEntity: closing brace without data"); + + key = ED_FindGlobal (keyname); + if (!key) + { + Con_Printf ("'%s' is not a global\n", keyname); + continue; + } + + if (!ED_ParseEpair ((void *)pr_globals, key, com_token)) + Host_Error ("ED_ParseGlobals: parse error"); + } +} + +//============================================================================ + + +/* +============= +ED_NewString +============= +*/ +char *ED_NewString (char *string) +{ + char *new, *new_p; + int i,l; + + l = strlen(string) + 1; + new = Hunk_Alloc (l); + new_p = new; + + for (i=0 ; i< l ; i++) + { + if (string[i] == '\\' && i < l-1) + { + i++; + if (string[i] == 'n') + *new_p++ = '\n'; + else + *new_p++ = '\\'; + } + else + *new_p++ = string[i]; + } + + return new; +} + + +/* +============= +ED_ParseEval + +Can parse either fields or globals +returns false if error +============= +*/ +qboolean ED_ParseEpair (void *base, ddef_t *key, char *s) +{ + int i; + char string[128]; + ddef_t *def; + char *v, *w; + void *d; + dfunction_t *func; + + d = (void *)((int *)base + key->ofs); + + switch (key->type & ~DEF_SAVEGLOBAL) + { + case ev_string: + *(string_t *)d = ED_NewString (s) - pr_strings; + break; + + case ev_float: + *(float *)d = (float)atof (s); + break; + + case ev_vector: + strcpy (string, s); + v = string; + w = string; + for (i=0 ; i<3 ; i++) + { + while (*v && *v != ' ') + v++; + *v = 0; + ((float *)d)[i] = (float)atof (w); + w = v = v+1; + } + break; + + case ev_entity: + *(int *)d = EDICT_TO_PROG(EDICT_NUM(atoi (s))); + break; + + case ev_field: + def = ED_FindField (s); + if (!def) + { + Con_Printf ("Can't find field %s\n", s); + return false; + } + *(int *)d = G_INT(def->ofs); + break; + + case ev_function: + func = ED_FindFunction (s); + if (!func) + { + Con_Printf ("Can't find function %s\n", s); + return false; + } + *(func_t *)d = func - pr_functions; + break; + + default: + break; + } + return true; +} + +#ifdef USEFPM +qboolean ED_ParseEpairFPM (void *base, ddef_t *key, char *s) +{ + int i; + char string[128]; + ddef_t *def; + char *v, *w; + void *d; + dfunction_t *func; + + d = (void *)((int *)base + key->ofs); + + switch (key->type & ~DEF_SAVEGLOBAL) + { + case ev_string: + *(string_t *)d = ED_NewString (s) - pr_strings; + break; + + case ev_float: + *(float *)d = (float)atof (s); + break; + + case ev_vector: + strcpy (string, s); + v = string; + w = string; + for (i=0 ; i<3 ; i++) + { + while (*v && *v != ' ') + v++; + *v = 0; + ((float *)d)[i] = (float)atof (w); + w = v = v+1; + } + break; + + case ev_entity: + *(int *)d = EDICT_TO_PROGFPM(EDICT_NUMFPM(atoi (s))); + break; + + case ev_field: + def = ED_FindField (s); + if (!def) + { + Con_Printf ("Can't find field %s\n", s); + return false; + } + *(int *)d = G_INT(def->ofs); + break; + + case ev_function: + func = ED_FindFunction (s); + if (!func) + { + Con_Printf ("Can't find function %s\n", s); + return false; + } + *(func_t *)d = func - pr_functions; + break; + + default: + break; + } + return true; +} +#endif //USEFPM + +/* +==================== +ED_ParseEdict + +Parses an edict out of the given string, returning the new position +ed should be a properly initialized empty edict. +Used for initial level load and for savegames. +==================== +*/ +char *ED_ParseEdict (char *data, edict_t *ent) +{ + ddef_t *key; + qboolean anglehack; + qboolean init; + char keyname[256]; + int n; + + init = false; + +// clear it + if (ent != sv.edicts) // hack + Q_memset (&ent->v, 0, progs->entityfields * 4); + +// go through all the dictionary pairs + while (1) + { + // parse key + data = COM_Parse (data); + if (com_token[0] == '}') + break; + if (!data) + Sys_Error ("ED_ParseEntity: EOF without closing brace"); + +// anglehack is to allow QuakeEd to write single scalar angles +// and allow them to be turned into vectors. (FIXME...) +if (!strcmp(com_token, "angle")) +{ + strcpy (com_token, "angles"); + anglehack = true; +} +else + anglehack = false; + +// FIXME: change light to _light to get rid of this hack +if (!strcmp(com_token, "light")) + strcpy (com_token, "light_lev"); // hack for single light def + + strcpy (keyname, com_token); + + // another hack to fix heynames with trailing spaces + n = strlen(keyname); + while (n && keyname[n-1] == ' ') + { + keyname[n-1] = 0; + n--; + } + + // parse value + data = COM_Parse (data); + if (!data) + Sys_Error ("ED_ParseEntity: EOF without closing brace"); + + if (com_token[0] == '}') + Sys_Error ("ED_ParseEntity: closing brace without data"); + + init = true; + +// keynames with a leading underscore are used for utility comments, +// and are immediately discarded by quake + if (keyname[0] == '_') + continue; + + key = ED_FindField (keyname); + if (!key) + { + Con_Printf ("'%s' is not a field\n", keyname); + continue; + } + +if (anglehack) +{ +char temp[32]; +strcpy (temp, com_token); +sprintf (com_token, "0 %s 0", temp); +} + + if (!ED_ParseEpair ((void *)&ent->v, key, com_token)) + Host_Error ("ED_ParseEdict: parse error"); + } + + if (!init) + ent->free = true; + + return data; +} + +#ifdef USEFPM +char *ED_ParseEdictFPM (char *data, edict_FPM_t *ent) +{ + ddef_t *key; + qboolean anglehack; + qboolean init; + char keyname[256]; + int n; + + init = false; + +// clear it + if (ent != svFPM.edicts) // hack + Q_memset (&ent->v, 0, progs->entityfields * 4); + +// go through all the dictionary pairs + while (1) + { + // parse key + data = COM_Parse (data); + if (com_token[0] == '}') + break; + if (!data) + Sys_Error ("ED_ParseEntity: EOF without closing brace"); + +// anglehack is to allow QuakeEd to write single scalar angles +// and allow them to be turned into vectors. (FIXME...) +if (!strcmp(com_token, "angle")) +{ + strcpy (com_token, "angles"); + anglehack = true; +} +else + anglehack = false; + +// FIXME: change light to _light to get rid of this hack +if (!strcmp(com_token, "light")) + strcpy (com_token, "light_lev"); // hack for single light def + + strcpy (keyname, com_token); + + // another hack to fix heynames with trailing spaces + n = strlen(keyname); + while (n && keyname[n-1] == ' ') + { + keyname[n-1] = 0; + n--; + } + + // parse value + data = COM_Parse (data); + if (!data) + Sys_Error ("ED_ParseEntity: EOF without closing brace"); + + if (com_token[0] == '}') + Sys_Error ("ED_ParseEntity: closing brace without data"); + + init = true; + +// keynames with a leading underscore are used for utility comments, +// and are immediately discarded by quake + if (keyname[0] == '_') + continue; + + key = ED_FindField (keyname); + if (!key) + { + Con_Printf ("'%s' is not a field\n", keyname); + continue; + } + + if (anglehack) + { + char temp[32]; + strcpy (temp, com_token); + sprintf (com_token, "0 %s 0", temp); + } + + if (!ED_ParseEpair ((void *)&ent->v, key, com_token)) + Host_Error ("ED_ParseEdict: parse error"); + } + + if (!init) + ent->free = true; + + return data; +} +#endif //USEFPM + +/* +================ +ED_LoadFromFile + +The entities are directly placed in the array, rather than allocated with +ED_Alloc, because otherwise an error loading the map would have entity +number references out of order. + +Creates a server's entity / program execution context by +parsing textual entity definitions out of an ent file. + +Used for both fresh maps and savegame loads. A fresh map would also need +to call ED_CallSpawnFunctions () to let the objects initialize themselves. +================ +*/ +void ED_LoadFromFile (char *data) +{ + edict_t *ent; + int inhibit; + dfunction_t *func; + + ent = NULL; + inhibit = 0; + pr_global_struct->time = (float)sv.time; + +// parse ents + while (1) + { +// parse the opening brace + data = COM_Parse (data); + if (!data) + break; + if (com_token[0] != '{') + Sys_Error ("ED_LoadFromFile: found %s when expecting {",com_token); + + if (!ent) + ent = EDICT_NUM(0); + else + ent = ED_Alloc (); + data = ED_ParseEdict (data, ent); + +// remove things from different skill levels or deathmatch + if (deathmatch.value) + { + if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH)) + { + ED_Free (ent); + inhibit++; + continue; + } + } + else if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY)) + || (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM)) + || (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD)) ) + { + ED_Free (ent); + inhibit++; + continue; + } + +// +// immediately call spawn function +// + if (!ent->v.classname) + { + Con_Printf ("No classname for:\n"); + ED_Print (ent); + ED_Free (ent); + continue; + } + + // look for the spawn function + func = ED_FindFunction ( pr_strings + ent->v.classname ); + + if (!func) + { + Con_Printf ("No spawn function for:\n"); + ED_Print (ent); + ED_Free (ent); + continue; + } + + pr_global_struct->self = EDICT_TO_PROG(ent); + PR_ExecuteProgram (func - pr_functions); + } + + Con_DPrintf ("%i entities inhibited\n", inhibit); +} + +#ifdef USEFPM +void ED_LoadFromFileFPM (char *data) +{ + edict_FPM_t *ent; + int inhibit; + dfunction_t *func; + + ent = NULL; + inhibit = 0; + pr_global_struct->time = (float)svFPM.time; + +// parse ents + while (1) + { +// parse the opening brace + data = COM_Parse (data); + if (!data) + break; + if (com_token[0] != '{') + Sys_Error ("ED_LoadFromFile: found %s when expecting {",com_token); + + if (!ent) + ent = EDICT_NUMFPM(0); + else + ent = ED_AllocFPM (); + data = ED_ParseEdictFPM (data, ent); + +// remove things from different skill levels or deathmatch + if (deathmatch.value) + { + if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH)) + { + ED_FreeFPM (ent); + inhibit++; + continue; + } + } + else if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY)) + || (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM)) + || (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD)) ) + { + ED_FreeFPM (ent); + inhibit++; + continue; + } + +// +// immediately call spawn function +// + if (!ent->v.classname) + { + Con_Printf ("No classname for:\n"); + ED_PrintFPM (ent); + ED_FreeFPM (ent); + continue; + } + + // look for the spawn function + func = ED_FindFunction ( pr_strings + ent->v.classname ); + + if (!func) + { + Con_Printf ("No spawn function for:\n"); + ED_PrintFPM (ent); + ED_FreeFPM (ent); + continue; + } + + pr_global_struct->self = EDICT_TO_PROGFPM(ent); + PR_ExecuteProgramFPM (func - pr_functions); + } + + Con_DPrintf ("%i entities inhibited\n", inhibit); +} +#endif //USEFPM + +/* +=============== +PR_LoadProgs +=============== +*/ +void PR_LoadProgs (void) +{ + int i; + +// flush the non-C variable lookup cache + for (i=0 ; iversion != PROG_VERSION) + Sys_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION); + if (progs->crc != PROGHEADER_CRC) + Sys_Error ("progs.dat system vars have been modified, progdefs.h is out of date"); + + + pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions); + pr_strings = (char *)progs + progs->ofs_strings; + pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs); + pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs); + pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements); + + + pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals); + pr_globals = (float *)pr_global_struct; + + pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t); + +// byte swap the lumps + for (i=0 ; inumstatements ; i++) + { + pr_statements[i].op = LittleShort(pr_statements[i].op); + pr_statements[i].a = LittleShort(pr_statements[i].a); + pr_statements[i].b = LittleShort(pr_statements[i].b); + pr_statements[i].c = LittleShort(pr_statements[i].c); + } + + + for (i=0 ; inumfunctions; i++) + { + pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement); + pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start); + pr_functions[i].s_name = LittleLong (pr_functions[i].s_name); + pr_functions[i].s_file = LittleLong (pr_functions[i].s_file); + pr_functions[i].numparms = LittleLong (pr_functions[i].numparms); + pr_functions[i].locals = LittleLong (pr_functions[i].locals); + } + + + for (i=0 ; inumglobaldefs ; i++) + { + pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type); + pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs); + pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name); + } + + + for (i=0 ; inumfielddefs ; i++) + { + pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type); + if (pr_fielddefs[i].type & DEF_SAVEGLOBAL) + Sys_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL"); + pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs); + pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name); + } + + + for (i=0 ; inumglobals ; i++) + ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]); + + + } + + +/* +=============== +PR_Init +=============== +*/ +void PR_Init (void) +{ + Cmd_AddCommand ("edict", ED_PrintEdict_f); + Cmd_AddCommand ("edicts", ED_PrintEdicts); + Cmd_AddCommand ("edictcount", ED_Count); + Cmd_AddCommand ("profile", PR_Profile_f); + Cvar_RegisterVariable (&nomonsters); + Cvar_RegisterVariable (&gamecfg); + Cvar_RegisterVariable (&scratch1); + Cvar_RegisterVariable (&scratch2); + Cvar_RegisterVariable (&scratch3); + Cvar_RegisterVariable (&scratch4); + Cvar_RegisterVariable (&savedgamecfg); + Cvar_RegisterVariable (&saved1); + Cvar_RegisterVariable (&saved2); + Cvar_RegisterVariable (&saved3); + Cvar_RegisterVariable (&saved4); +} + + + +edict_t *EDICT_NUM(int n) +{ + if (n < 0 || n >= sv.max_edicts) + Sys_Error ("EDICT_NUM: bad number %i", n); + return (edict_t *)((byte *)sv.edicts+ (n)*pr_edict_size); +} + +#ifdef USEFPM +edict_FPM_t *EDICT_NUMFPM(int n) +{ + if (n < 0 || n >= svFPM.max_edicts) + Sys_Error ("EDICT_NUM: bad number %i", n); + return (edict_FPM_t *)((byte *)svFPM.edicts+ (n)*pr_edict_size); +} +#endif //USEFPM + +int NUM_FOR_EDICT(edict_t *e) +{ + int b; + + b = (byte *)e - (byte *)sv.edicts; + b = b / pr_edict_size; + + if (b < 0 || b >= sv.num_edicts) + Sys_Error ("NUM_FOR_EDICT: bad pointer"); + return b; +} + +#ifdef USEFPM +int NUM_FOR_EDICTFPM(edict_FPM_t *e) +{ + int b; + + b = (byte *)e - (byte *)svFPM.edicts; + b = b / pr_edict_size; + + if (b < 0 || b >= svFPM.num_edicts) + Sys_Error ("NUM_FOR_EDICT: bad pointer"); + return b; +} +#endif //USEFPM diff --git a/project/jni/application/quake/source/pr_exec.c b/project/jni/application/quake/source/pr_exec.c new file mode 100644 index 000000000..2cedb8496 --- /dev/null +++ b/project/jni/application/quake/source/pr_exec.c @@ -0,0 +1,979 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" + + +/* + +*/ + +typedef struct +{ + int s; + dfunction_t *f; +} prstack_t; + +#define MAX_STACK_DEPTH 32 +prstack_t pr_stack[MAX_STACK_DEPTH]; +int pr_depth; + +#define LOCALSTACK_SIZE 2048 +int localstack[LOCALSTACK_SIZE]; +int localstack_used; + + +qboolean pr_trace; +dfunction_t *pr_xfunction; +int pr_xstatement; + + +int pr_argc; + +char *pr_opnames[] = +{ +"DONE", + +"MUL_F", +"MUL_V", +"MUL_FV", +"MUL_VF", + +"DIV", + +"ADD_F", +"ADD_V", + +"SUB_F", +"SUB_V", + +"EQ_F", +"EQ_V", +"EQ_S", +"EQ_E", +"EQ_FNC", + +"NE_F", +"NE_V", +"NE_S", +"NE_E", +"NE_FNC", + +"LE", +"GE", +"LT", +"GT", + +"INDIRECT", +"INDIRECT", +"INDIRECT", +"INDIRECT", +"INDIRECT", +"INDIRECT", + +"ADDRESS", + +"STORE_F", +"STORE_V", +"STORE_S", +"STORE_ENT", +"STORE_FLD", +"STORE_FNC", + +"STOREP_F", +"STOREP_V", +"STOREP_S", +"STOREP_ENT", +"STOREP_FLD", +"STOREP_FNC", + +"RETURN", + +"NOT_F", +"NOT_V", +"NOT_S", +"NOT_ENT", +"NOT_FNC", + +"IF", +"IFNOT", + +"CALL0", +"CALL1", +"CALL2", +"CALL3", +"CALL4", +"CALL5", +"CALL6", +"CALL7", +"CALL8", + +"STATE", + +"GOTO", + +"AND", +"OR", + +"BITAND", +"BITOR" +}; + +char *PR_GlobalString (int ofs); +char *PR_GlobalStringNoContents (int ofs); + + +//============================================================================= + +/* +================= +PR_PrintStatement +================= +*/ +void PR_PrintStatement (dstatement_t *s) +{ + int i; + + if ( (unsigned)s->op < sizeof(pr_opnames)/sizeof(pr_opnames[0])) + { + Con_Printf ("%s ", pr_opnames[s->op]); + i = strlen(pr_opnames[s->op]); + for ( ; i<10 ; i++) + Con_Printf (" "); + } + + if (s->op == OP_IF || s->op == OP_IFNOT) + Con_Printf ("%sbranch %i",PR_GlobalString(s->a),s->b); + else if (s->op == OP_GOTO) + { + Con_Printf ("branch %i",s->a); + } + else if ( (unsigned)(s->op - OP_STORE_F) < 6) + { + Con_Printf ("%s",PR_GlobalString(s->a)); + Con_Printf ("%s", PR_GlobalStringNoContents(s->b)); + } + else + { + if (s->a) + Con_Printf ("%s",PR_GlobalString(s->a)); + if (s->b) + Con_Printf ("%s",PR_GlobalString(s->b)); + if (s->c) + Con_Printf ("%s", PR_GlobalStringNoContents(s->c)); + } + Con_Printf ("\n"); +} + +/* +============ +PR_StackTrace +============ +*/ +void PR_StackTrace (void) +{ + dfunction_t *f; + int i; + + if (pr_depth == 0) + { + Con_Printf ("\n"); + return; + } + + pr_stack[pr_depth].f = pr_xfunction; + for (i=pr_depth ; i>=0 ; i--) + { + f = pr_stack[i].f; + + if (!f) + { + Con_Printf ("\n"); + } + else + Con_Printf ("%12s : %s\n", pr_strings + f->s_file, pr_strings + f->s_name); + } +} + + +/* +============ +PR_Profile_f + +============ +*/ +void PR_Profile_f (void) +{ + dfunction_t *f, *best; + int max; + int num; + int i; + + num = 0; + do + { + max = 0; + best = NULL; + for (i=0 ; inumfunctions ; i++) + { + f = &pr_functions[i]; + if (f->profile > max) + { + max = f->profile; + best = f; + } + } + if (best) + { + if (num < 10) + Con_Printf ("%7i %s\n", best->profile, pr_strings+best->s_name); + num++; + best->profile = 0; + } + } while (best); +} + + +/* +============ +PR_RunError + +Aborts the currently executing function +============ +*/ +void PR_RunError (char *error, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,error); + vsprintf (string,error,argptr); + va_end (argptr); + + PR_PrintStatement (pr_statements + pr_xstatement); + PR_StackTrace (); + Con_Printf ("%s\n", string); + + pr_depth = 0; // dump the stack so host_error can shutdown functions + + Host_Error ("Program error"); +} + +/* +============================================================================ +PR_ExecuteProgram + +The interpretation main loop +============================================================================ +*/ + +/* +==================== +PR_EnterFunction + +Returns the new program statement counter +==================== +*/ +int PR_EnterFunction (dfunction_t *f) +{ + int i, j, c, o; + + pr_stack[pr_depth].s = pr_xstatement; + pr_stack[pr_depth].f = pr_xfunction; + pr_depth++; + if (pr_depth >= MAX_STACK_DEPTH) + PR_RunError ("stack overflow"); + +// save off any locals that the new function steps on + c = f->locals; + if (localstack_used + c > LOCALSTACK_SIZE) + PR_RunError ("PR_ExecuteProgram: locals stack overflow\n"); + + for (i=0 ; i < c ; i++) + localstack[localstack_used+i] = ((int *)pr_globals)[f->parm_start + i]; + localstack_used += c; + +// copy parameters + o = f->parm_start; + for (i=0 ; inumparms ; i++) + { + for (j=0 ; jparm_size[i] ; j++) + { + ((int *)pr_globals)[o] = ((int *)pr_globals)[OFS_PARM0+i*3+j]; + o++; + } + } + + pr_xfunction = f; + return f->first_statement - 1; // offset the s++ +} + +/* +==================== +PR_LeaveFunction +==================== +*/ +int PR_LeaveFunction (void) +{ + int i, c; + + if (pr_depth <= 0) + Sys_Error ("prog stack underflow"); + +// restore locals from the stack + c = pr_xfunction->locals; + localstack_used -= c; + if (localstack_used < 0) + PR_RunError ("PR_ExecuteProgram: locals stack underflow\n"); + + for (i=0 ; i < c ; i++) + ((int *)pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used+i]; + +// up stack + pr_depth--; + pr_xfunction = pr_stack[pr_depth].f; + return pr_stack[pr_depth].s; +} + + +/* +==================== +PR_ExecuteProgram +==================== +*/ +void PR_ExecuteProgram (func_t fnum) +{ + eval_t *a, *b, *c; + int s; + dstatement_t *st; + dfunction_t *f, *newf; + int runaway; + int i; + edict_t *ed; + int exitdepth; + eval_t *ptr; + + if (!fnum || fnum >= progs->numfunctions) + { + if (pr_global_struct->self) + ED_Print (PROG_TO_EDICT(pr_global_struct->self)); + Host_Error ("PR_ExecuteProgram: NULL function"); + } + + f = &pr_functions[fnum]; + + runaway = 100000; + pr_trace = false; + +// make a stack frame + exitdepth = pr_depth; + + s = PR_EnterFunction (f); + +while (1) +{ + s++; // next statement + + st = &pr_statements[s]; + a = (eval_t *)&pr_globals[st->a]; + b = (eval_t *)&pr_globals[st->b]; + c = (eval_t *)&pr_globals[st->c]; + + if (!--runaway) + PR_RunError ("runaway loop error"); + + pr_xfunction->profile++; + pr_xstatement = s; + + if (pr_trace) + PR_PrintStatement (st); + + switch (st->op) + { + case OP_ADD_F: + c->_float = a->_float + b->_float; + break; + case OP_ADD_V: + c->vector[0] = a->vector[0] + b->vector[0]; + c->vector[1] = a->vector[1] + b->vector[1]; + c->vector[2] = a->vector[2] + b->vector[2]; + break; + + case OP_SUB_F: + c->_float = a->_float - b->_float; + break; + case OP_SUB_V: + c->vector[0] = a->vector[0] - b->vector[0]; + c->vector[1] = a->vector[1] - b->vector[1]; + c->vector[2] = a->vector[2] - b->vector[2]; + break; + + case OP_MUL_F: + c->_float = a->_float * b->_float; + break; + case OP_MUL_V: + c->_float = a->vector[0]*b->vector[0] + + a->vector[1]*b->vector[1] + + a->vector[2]*b->vector[2]; + break; + case OP_MUL_FV: + c->vector[0] = a->_float * b->vector[0]; + c->vector[1] = a->_float * b->vector[1]; + c->vector[2] = a->_float * b->vector[2]; + break; + case OP_MUL_VF: + c->vector[0] = b->_float * a->vector[0]; + c->vector[1] = b->_float * a->vector[1]; + c->vector[2] = b->_float * a->vector[2]; + break; + + case OP_DIV_F: + c->_float = a->_float / b->_float; + break; + + case OP_BITAND: + c->_float = (float)((int)a->_float & (int)b->_float); + break; + + case OP_BITOR: + c->_float = (float)((int)a->_float | (int)b->_float); + break; + + + case OP_GE: + c->_float = (float)(a->_float >= b->_float); + break; + case OP_LE: + c->_float = (float)(a->_float <= b->_float); + break; + case OP_GT: + c->_float = (float)(a->_float > b->_float); + break; + case OP_LT: + c->_float = (float)(a->_float < b->_float); + break; + case OP_AND: + c->_float = (float)(a->_float && b->_float); + break; + case OP_OR: + c->_float = (float)(a->_float || b->_float); + break; + + case OP_NOT_F: + c->_float = (float)!a->_float; + break; + case OP_NOT_V: + c->_float = (float)(!a->vector[0] && !a->vector[1] && !a->vector[2]); + break; + case OP_NOT_S: + c->_float = (float)(!a->string || !pr_strings[a->string]); + break; + case OP_NOT_FNC: + c->_float = (float)!a->function; + break; + case OP_NOT_ENT: + c->_float = (float)(PROG_TO_EDICT(a->edict) == sv.edicts); + break; + + case OP_EQ_F: + c->_float = (float)(a->_float == b->_float); + break; + case OP_EQ_V: + c->_float = (float)((a->vector[0] == b->vector[0]) && + (a->vector[1] == b->vector[1]) && + (a->vector[2] == b->vector[2])); + break; + case OP_EQ_S: + c->_float = (float)!strcmp(pr_strings+a->string,pr_strings+b->string); + break; + case OP_EQ_E: + c->_float = (float)(a->_int == b->_int); + break; + case OP_EQ_FNC: + c->_float = (float)(a->function == b->function); + break; + + + case OP_NE_F: + c->_float = (float)(a->_float != b->_float); + break; + case OP_NE_V: + c->_float = (float)((a->vector[0] != b->vector[0]) || + (a->vector[1] != b->vector[1]) || + (a->vector[2] != b->vector[2])); + break; + case OP_NE_S: + c->_float = (float)strcmp(pr_strings+a->string,pr_strings+b->string); + break; + case OP_NE_E: + c->_float = (float)(a->_int != b->_int); + break; + case OP_NE_FNC: + c->_float = (float)(a->function != b->function); + break; + +//================== + case OP_STORE_F: + case OP_STORE_ENT: + case OP_STORE_FLD: // integers + case OP_STORE_S: + case OP_STORE_FNC: // pointers + b->_int = a->_int; + break; + case OP_STORE_V: + b->vector[0] = a->vector[0]; + b->vector[1] = a->vector[1]; + b->vector[2] = a->vector[2]; + break; + + case OP_STOREP_F: + case OP_STOREP_ENT: + case OP_STOREP_FLD: // integers + case OP_STOREP_S: + case OP_STOREP_FNC: // pointers + ptr = (eval_t *)((byte *)sv.edicts + b->_int); + ptr->_int = a->_int; + break; + case OP_STOREP_V: + ptr = (eval_t *)((byte *)sv.edicts + b->_int); + ptr->vector[0] = a->vector[0]; + ptr->vector[1] = a->vector[1]; + ptr->vector[2] = a->vector[2]; + break; + + case OP_ADDRESS: + ed = PROG_TO_EDICT(a->edict); +#ifdef PARANOID + NUM_FOR_EDICT(ed); // make sure it's in range +#endif + if (ed == (edict_t *)sv.edicts && sv.state == ss_active) + PR_RunError ("assignment to world entity"); + c->_int = (byte *)((int *)&ed->v + b->_int) - (byte *)sv.edicts; + break; + + case OP_LOAD_F: + case OP_LOAD_FLD: + case OP_LOAD_ENT: + case OP_LOAD_S: + case OP_LOAD_FNC: + ed = PROG_TO_EDICT(a->edict); +#ifdef PARANOID + NUM_FOR_EDICT(ed); // make sure it's in range +#endif + a = (eval_t *)((int *)&ed->v + b->_int); + c->_int = a->_int; + break; + + case OP_LOAD_V: + ed = PROG_TO_EDICT(a->edict); +#ifdef PARANOID + NUM_FOR_EDICT(ed); // make sure it's in range +#endif + a = (eval_t *)((int *)&ed->v + b->_int); + c->vector[0] = a->vector[0]; + c->vector[1] = a->vector[1]; + c->vector[2] = a->vector[2]; + break; + +//================== + + case OP_IFNOT: + if (!a->_int) + s += st->b - 1; // offset the s++ + break; + + case OP_IF: + if (a->_int) + s += st->b - 1; // offset the s++ + break; + + case OP_GOTO: + s += st->a - 1; // offset the s++ + break; + + case OP_CALL0: + case OP_CALL1: + case OP_CALL2: + case OP_CALL3: + case OP_CALL4: + case OP_CALL5: + case OP_CALL6: + case OP_CALL7: + case OP_CALL8: + pr_argc = st->op - OP_CALL0; + if (!a->function) + PR_RunError ("NULL function"); + + newf = &pr_functions[a->function]; + + if (newf->first_statement < 0) + { // negative statements are built in functions + i = -newf->first_statement; + if (i >= pr_numbuiltins) + PR_RunError ("Bad builtin call number"); + pr_builtins[i] (); + break; + } + + s = PR_EnterFunction (newf); + break; + + case OP_DONE: + case OP_RETURN: + pr_globals[OFS_RETURN] = pr_globals[st->a]; + pr_globals[OFS_RETURN+1] = pr_globals[st->a+1]; + pr_globals[OFS_RETURN+2] = pr_globals[st->a+2]; + + s = PR_LeaveFunction (); + if (pr_depth == exitdepth) + return; // all done + break; + + case OP_STATE: + ed = PROG_TO_EDICT(pr_global_struct->self); +#ifdef FPS_20 + ed->v.nextthink = (float)(pr_global_struct->time + 0.05); +#else + ed->v.nextthink = (float)(pr_global_struct->time + 0.1); +#endif + if (a->_float != ed->v.frame) + { + ed->v.frame = a->_float; + } + ed->v.think = b->function; + break; + + default: + PR_RunError ("Bad opcode %i", st->op); + } +} + +} + +#ifdef USEFPM +void PR_ExecuteProgramFPM (func_t fnum) +{ + eval_t *a, *b, *c; + int s; + dstatement_t *st; + dfunction_t *f, *newf; + int runaway; + int i; + edict_FPM_t *ed; + int exitdepth; + eval_t *ptr; + + if (!fnum || fnum >= progs->numfunctions) + { + if (pr_global_struct->self) + ED_PrintFPM (PROG_TO_EDICTFPM(pr_global_struct->self)); + Host_Error ("PR_ExecuteProgram: NULL function"); + } + + f = &pr_functions[fnum]; + + runaway = 100000; + pr_trace = false; + +// make a stack frame + exitdepth = pr_depth; + + s = PR_EnterFunction (f); + +while (1) +{ + s++; // next statement + + st = &pr_statements[s]; + a = (eval_t *)&pr_globals[st->a]; + b = (eval_t *)&pr_globals[st->b]; + c = (eval_t *)&pr_globals[st->c]; + + if (!--runaway) + PR_RunError ("runaway loop error"); + + pr_xfunction->profile++; + pr_xstatement = s; + + if (pr_trace) + PR_PrintStatement (st); + + switch (st->op) + { + case OP_ADD_F: + c->_float = a->_float + b->_float; + break; + case OP_ADD_V: + c->vector[0] = a->vector[0] + b->vector[0]; + c->vector[1] = a->vector[1] + b->vector[1]; + c->vector[2] = a->vector[2] + b->vector[2]; + break; + + case OP_SUB_F: + c->_float = a->_float - b->_float; + break; + case OP_SUB_V: + c->vector[0] = a->vector[0] - b->vector[0]; + c->vector[1] = a->vector[1] - b->vector[1]; + c->vector[2] = a->vector[2] - b->vector[2]; + break; + + case OP_MUL_F: + c->_float = a->_float * b->_float; + break; + case OP_MUL_V: + c->_float = a->vector[0]*b->vector[0] + + a->vector[1]*b->vector[1] + + a->vector[2]*b->vector[2]; + break; + case OP_MUL_FV: + c->vector[0] = a->_float * b->vector[0]; + c->vector[1] = a->_float * b->vector[1]; + c->vector[2] = a->_float * b->vector[2]; + break; + case OP_MUL_VF: + c->vector[0] = b->_float * a->vector[0]; + c->vector[1] = b->_float * a->vector[1]; + c->vector[2] = b->_float * a->vector[2]; + break; + + case OP_DIV_F: + c->_float = a->_float / b->_float; + break; + + case OP_BITAND: + c->_float = (float)((int)a->_float & (int)b->_float); + break; + + case OP_BITOR: + c->_float = (float)((int)a->_float | (int)b->_float); + break; + + + case OP_GE: + c->_float = (float)(a->_float >= b->_float); + break; + case OP_LE: + c->_float = (float)(a->_float <= b->_float); + break; + case OP_GT: + c->_float = (float)(a->_float > b->_float); + break; + case OP_LT: + c->_float = (float)(a->_float < b->_float); + break; + case OP_AND: + c->_float = (float)(a->_float && b->_float); + break; + case OP_OR: + c->_float = (float)(a->_float || b->_float); + break; + + case OP_NOT_F: + c->_float = (float)(!a->_float); + break; + case OP_NOT_V: + c->_float = (float)(!a->vector[0] && !a->vector[1] && !a->vector[2]); + break; + case OP_NOT_S: + c->_float = (float)(!a->string || !pr_strings[a->string]); + break; + case OP_NOT_FNC: + c->_float = (float)(!a->function); + break; + case OP_NOT_ENT: + c->_float = (float)(PROG_TO_EDICT(a->edict) == sv.edicts); + break; + + case OP_EQ_F: + c->_float = (float)(a->_float == b->_float); + break; + case OP_EQ_V: + c->_float = (float)((a->vector[0] == b->vector[0]) && + (a->vector[1] == b->vector[1]) && + (a->vector[2] == b->vector[2])); + break; + case OP_EQ_S: + c->_float = (float)!strcmp(pr_strings+a->string,pr_strings+b->string); + break; + case OP_EQ_E: + c->_float = (float)(a->_int == b->_int); + break; + case OP_EQ_FNC: + c->_float = (float)(a->function == b->function); + break; + + + case OP_NE_F: + c->_float = (float)(a->_float != b->_float); + break; + case OP_NE_V: + c->_float = (float)((a->vector[0] != b->vector[0]) || + (a->vector[1] != b->vector[1]) || + (a->vector[2] != b->vector[2])); + break; + case OP_NE_S: + c->_float = (float)strcmp(pr_strings+a->string,pr_strings+b->string); + break; + case OP_NE_E: + c->_float = (float)(a->_int != b->_int); + break; + case OP_NE_FNC: + c->_float = (float)(a->function != b->function); + break; + +//================== + case OP_STORE_F: + case OP_STORE_ENT: + case OP_STORE_FLD: // integers + case OP_STORE_S: + case OP_STORE_FNC: // pointers + b->_int = a->_int; + break; + case OP_STORE_V: + b->vector[0] = a->vector[0]; + b->vector[1] = a->vector[1]; + b->vector[2] = a->vector[2]; + break; + + case OP_STOREP_F: + case OP_STOREP_ENT: + case OP_STOREP_FLD: // integers + case OP_STOREP_S: + case OP_STOREP_FNC: // pointers + ptr = (eval_t *)((byte *)svFPM.edicts + b->_int); + ptr->_int = a->_int; + break; + case OP_STOREP_V: + ptr = (eval_t *)((byte *)svFPM.edicts + b->_int); + ptr->vector[0] = a->vector[0]; + ptr->vector[1] = a->vector[1]; + ptr->vector[2] = a->vector[2]; + break; + + case OP_ADDRESS: + ed = PROG_TO_EDICTFPM(a->edict); +#ifdef PARANOID + NUM_FOR_EDICT(ed); // make sure it's in range +#endif + if (ed == (edict_FPM_t *)svFPM.edicts && svFPM.state == ss_active) + PR_RunError ("assignment to world entity"); + c->_int = (byte *)((int *)&ed->v + b->_int) - (byte *)svFPM.edicts; + break; + + case OP_LOAD_F: + case OP_LOAD_FLD: + case OP_LOAD_ENT: + case OP_LOAD_S: + case OP_LOAD_FNC: + ed = PROG_TO_EDICTFPM(a->edict); +#ifdef PARANOID + NUM_FOR_EDICTFPM(ed); // make sure it's in range +#endif + a = (eval_t *)((int *)&ed->v + b->_int); + c->_int = a->_int; + break; + + case OP_LOAD_V: + ed = PROG_TO_EDICTFPM(a->edict); +#ifdef PARANOID + NUM_FOR_EDICTFPM(ed); // make sure it's in range +#endif + a = (eval_t *)((int *)&ed->v + b->_int); + c->vector[0] = a->vector[0]; + c->vector[1] = a->vector[1]; + c->vector[2] = a->vector[2]; + break; + +//================== + + case OP_IFNOT: + if (!a->_int) + s += st->b - 1; // offset the s++ + break; + + case OP_IF: + if (a->_int) + s += st->b - 1; // offset the s++ + break; + + case OP_GOTO: + s += st->a - 1; // offset the s++ + break; + + case OP_CALL0: + case OP_CALL1: + case OP_CALL2: + case OP_CALL3: + case OP_CALL4: + case OP_CALL5: + case OP_CALL6: + case OP_CALL7: + case OP_CALL8: + pr_argc = st->op - OP_CALL0; + if (!a->function) + PR_RunError ("NULL function"); + + newf = &pr_functions[a->function]; + + if (newf->first_statement < 0) + { // negative statements are built in functions + i = -newf->first_statement; + if (i >= pr_numbuiltins) + PR_RunError ("Bad builtin call number"); + pr_builtinsFPM[i] (); + break; + } + + s = PR_EnterFunction (newf); + break; + + case OP_DONE: + case OP_RETURN: + pr_globals[OFS_RETURN] = pr_globals[st->a]; + pr_globals[OFS_RETURN+1] = pr_globals[st->a+1]; + pr_globals[OFS_RETURN+2] = pr_globals[st->a+2]; + + s = PR_LeaveFunction (); + if (pr_depth == exitdepth) + return; // all done + break; + + case OP_STATE: + ed = PROG_TO_EDICTFPM(pr_global_struct->self); +#ifdef FPS_20 + ed->v.nextthink = (float)(pr_global_struct->time + 0.05); +#else + ed->v.nextthink = (float)(pr_global_struct->time + 0.1); +#endif + if (a->_float != ed->v.frame) + { + ed->v.frame = a->_float; + } + ed->v.think = b->function; + break; + + default: + PR_RunError ("Bad opcode %i", st->op); + } +} + +} +#endif //USEFPM \ No newline at end of file diff --git a/project/jni/application/quake/source/progdefs.h b/project/jni/application/quake/source/progdefs.h new file mode 100644 index 000000000..6681b4464 --- /dev/null +++ b/project/jni/application/quake/source/progdefs.h @@ -0,0 +1,24 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifdef QUAKE2 +#include "progdefs.q2" +#else +#include "progdefs.q1" +#endif diff --git a/project/jni/application/quake/source/progdefs.q1 b/project/jni/application/quake/source/progdefs.q1 new file mode 100644 index 000000000..c976cf8e1 --- /dev/null +++ b/project/jni/application/quake/source/progdefs.q1 @@ -0,0 +1,143 @@ + +/* file generated by qcc, do not modify */ + +typedef struct +{ int pad[28]; + int self; + int other; + int world; + float time; + float frametime; + float force_retouch; + string_t mapname; + float deathmatch; + float coop; + float teamplay; + float serverflags; + float total_secrets; + float total_monsters; + float found_secrets; + float killed_monsters; + float parm1; + float parm2; + float parm3; + float parm4; + float parm5; + float parm6; + float parm7; + float parm8; + float parm9; + float parm10; + float parm11; + float parm12; + float parm13; + float parm14; + float parm15; + float parm16; + vec3_t v_forward; + vec3_t v_up; + vec3_t v_right; + float trace_allsolid; + float trace_startsolid; + float trace_fraction; + vec3_t trace_endpos; + vec3_t trace_plane_normal; + float trace_plane_dist; + int trace_ent; + float trace_inopen; + float trace_inwater; + int msg_entity; + func_t main; + func_t StartFrame; + func_t PlayerPreThink; + func_t PlayerPostThink; + func_t ClientKill; + func_t ClientConnect; + func_t PutClientInServer; + func_t ClientDisconnect; + func_t SetNewParms; + func_t SetChangeParms; +} globalvars_t; + +typedef struct +{ + float modelindex; + vec3_t absmin; + vec3_t absmax; + float ltime; + float movetype; + float solid; + vec3_t origin; + vec3_t oldorigin; + vec3_t velocity; + vec3_t angles; + vec3_t avelocity; + vec3_t punchangle; + string_t classname; + string_t model; + float frame; + float skin; + float effects; + vec3_t mins; + vec3_t maxs; + vec3_t size; + func_t touch; + func_t use; + func_t think; + func_t blocked; + float nextthink; + int groundentity; + float health; + float frags; + float weapon; + string_t weaponmodel; + float weaponframe; + float currentammo; + float ammo_shells; + float ammo_nails; + float ammo_rockets; + float ammo_cells; + float items; + float takedamage; + int chain; + float deadflag; + vec3_t view_ofs; + float button0; + float button1; + float button2; + float impulse; + float fixangle; + vec3_t v_angle; + float idealpitch; + string_t netname; + int enemy; + float flags; + float colormap; + float team; + float max_health; + float teleport_time; + float armortype; + float armorvalue; + float waterlevel; + float watertype; + float ideal_yaw; + float yaw_speed; + int aiment; + int goalentity; + float spawnflags; + string_t target; + string_t targetname; + float dmg_take; + float dmg_save; + int dmg_inflictor; + int owner; + vec3_t movedir; + string_t message; + float sounds; + string_t noise; + string_t noise1; + string_t noise2; + string_t noise3; +} entvars_t; + +#define PROGHEADER_CRC 5927 diff --git a/project/jni/application/quake/source/progs.h b/project/jni/application/quake/source/progs.h new file mode 100644 index 000000000..c0a416e05 --- /dev/null +++ b/project/jni/application/quake/source/progs.h @@ -0,0 +1,170 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "pr_comp.h" // defs shared with qcc +#include "progdefs.h" // generated by program cdefs + +typedef union eval_s +{ + string_t string; + float _float; + float vector[3]; + func_t function; + int _int; + int edict; +} eval_t; + +#define MAX_ENT_LEAFS 16 +typedef struct edict_s +{ + qboolean free; + link_t area; // linked to a division node or leaf + + int num_leafs; + short leafnums[MAX_ENT_LEAFS]; + + entity_state_t baseline; + + float freetime; // sv.time when the object was freed + entvars_t v; // C exported fields from progs +// other fields from progs come immediately after +} edict_t; + +typedef struct edict_FPM_s +{ + qboolean free; + link_t area; // linked to a division node or leaf + + int num_leafs; + short leafnums[MAX_ENT_LEAFS]; + + entity_state_FPM_t baseline; + + float freetime; // sv.time when the object was freed + entvars_t v; // C exported fields from progs +// other fields from progs come immediately after +} edict_FPM_t; + +#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area) +#define EDICT_FROM_AREAFPM(l) STRUCT_FROM_LINK(l,edict_FPM_t,area) + +//============================================================================ + +extern dprograms_t *progs; +extern dfunction_t *pr_functions; +extern char *pr_strings; +extern ddef_t *pr_globaldefs; +extern ddef_t *pr_fielddefs; +extern dstatement_t *pr_statements; +extern globalvars_t *pr_global_struct; +extern float *pr_globals; // same as pr_global_struct + +extern int pr_edict_size; // in bytes + +//============================================================================ + +void PR_Init (void); + +void PR_ExecuteProgram (func_t fnum); +void PR_ExecuteProgramFPM (func_t fnum); +void PR_LoadProgs (void); + +void PR_Profile_f (void); + +edict_t *ED_Alloc (void); +edict_FPM_t *ED_AllocFPM (void); +void ED_Free (edict_t *ed); +void ED_FreeFPM (edict_FPM_t *ed); + +char *ED_NewString (char *string); +// returns a copy of the string allocated from the server's string heap + +void ED_Print (edict_t *ed); +void ED_PrintFPM (edict_FPM_t *ed); +void ED_Write (FILE *f, edict_t *ed); +void ED_WriteFPM (FILE *f, edict_FPM_t *ed); +char *ED_ParseEdict (char *data, edict_t *ent); +char *ED_ParseEdictFPM (char *data, edict_FPM_t *ent); + +void ED_WriteGlobals (FILE *f); +void ED_ParseGlobals (char *data); + +void ED_LoadFromFile (char *data); +void ED_LoadFromFileFPM (char *data); + +//define EDICT_NUM(n) ((edict_t *)(sv.edicts+ (n)*pr_edict_size)) +//define NUM_FOR_EDICT(e) (((byte *)(e) - sv.edicts)/pr_edict_size) + +edict_t *EDICT_NUM(int n); +edict_FPM_t *EDICT_NUMFPM(int n); +int NUM_FOR_EDICT(edict_t *e); +int NUM_FOR_EDICTFPM(edict_FPM_t *e); + +#define NEXT_EDICT(e) ((edict_t *)( (byte *)e + pr_edict_size)) +#define NEXT_EDICTFPM(e) ((edict_FPM_t *)( (byte *)e + pr_edict_size)) + +#define EDICT_TO_PROG(e) ((byte *)e - (byte *)sv.edicts) +#define EDICT_TO_PROGFPM(e) ((byte *)e - (byte *)svFPM.edicts) +#define PROG_TO_EDICT(e) ((edict_t *)((byte *)sv.edicts + e)) +#define PROG_TO_EDICTFPM(e) ((edict_FPM_t *)((byte *)svFPM.edicts + e)) + +//============================================================================ + +#define G_FLOAT(o) (pr_globals[o]) +#define G_INT(o) (*(int *)&pr_globals[o]) +#define G_EDICT(o) ((edict_t *)((byte *)sv.edicts+ *(int *)&pr_globals[o])) +#define G_EDICTFPM(o) ((edict_FPM_t *)((byte *)svFPM.edicts+ *(int *)&pr_globals[o])) +#define G_EDICTNUM(o) NUM_FOR_EDICT(G_EDICT(o)) +#define G_EDICTNUMFPM(o) NUM_FOR_EDICTFPM(G_EDICTFPM(o)) +#define G_VECTOR(o) (&pr_globals[o]) +#define G_STRING(o) (pr_strings + *(string_t *)&pr_globals[o]) +#define G_FUNCTION(o) (*(func_t *)&pr_globals[o]) + +#define E_FLOAT(e,o) (((float*)&e->v)[o]) +#define E_INT(e,o) (*(int *)&((float*)&e->v)[o]) +#define E_VECTOR(e,o) (&((float*)&e->v)[o]) +#define E_STRING(e,o) (pr_strings + *(string_t *)&((float*)&e->v)[o]) + +extern int type_size[8]; + +typedef void (*builtin_t) (void); +typedef void (*builtin_FPM_t) (void); +extern builtin_t *pr_builtins; +extern builtin_FPM_t *pr_builtinsFPM; +extern int pr_numbuiltins; +extern int pr_numbuiltinsFPM; + +extern int pr_argc; + +extern qboolean pr_trace; +extern dfunction_t *pr_xfunction; +extern int pr_xstatement; + +extern unsigned short pr_crc; + +void PR_RunError (char *error, ...); + +void ED_PrintEdicts (void); +void ED_PrintEdictsFPM (void); +void ED_PrintNum (int ent); + +eval_t *GetEdictFieldValue(edict_t *ed, char *field); +eval_t *GetEdictFieldValueFPM(edict_FPM_t *ed, char *field); + diff --git a/project/jni/application/quake/source/protocol.h b/project/jni/application/quake/source/protocol.h new file mode 100644 index 000000000..ec3e58a15 --- /dev/null +++ b/project/jni/application/quake/source/protocol.h @@ -0,0 +1,167 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// protocol.h -- communications protocols + +#define PROTOCOL_VERSION 15 + +// if the high bit of the servercmd is set, the low bits are fast update flags: +#define U_MOREBITS (1<<0) +#define U_ORIGIN1 (1<<1) +#define U_ORIGIN2 (1<<2) +#define U_ORIGIN3 (1<<3) +#define U_ANGLE2 (1<<4) +#define U_NOLERP (1<<5) // don't interpolate movement +#define U_FRAME (1<<6) +#define U_SIGNAL (1<<7) // just differentiates from other updates + +// svc_update can pass all of the fast update bits, plus more +#define U_ANGLE1 (1<<8) +#define U_ANGLE3 (1<<9) +#define U_MODEL (1<<10) +#define U_COLORMAP (1<<11) +#define U_SKIN (1<<12) +#define U_EFFECTS (1<<13) +#define U_LONGENTITY (1<<14) + + +#define SU_VIEWHEIGHT (1<<0) +#define SU_IDEALPITCH (1<<1) +#define SU_PUNCH1 (1<<2) +#define SU_PUNCH2 (1<<3) +#define SU_PUNCH3 (1<<4) +#define SU_VELOCITY1 (1<<5) +#define SU_VELOCITY2 (1<<6) +#define SU_VELOCITY3 (1<<7) +//define SU_AIMENT (1<<8) AVAILABLE BIT +#define SU_ITEMS (1<<9) +#define SU_ONGROUND (1<<10) // no data follows, the bit is it +#define SU_INWATER (1<<11) // no data follows, the bit is it +#define SU_WEAPONFRAME (1<<12) +#define SU_ARMOR (1<<13) +#define SU_WEAPON (1<<14) + +// a sound with no channel is a local only sound +#define SND_VOLUME (1<<0) // a byte +#define SND_ATTENUATION (1<<1) // a byte +#define SND_LOOPING (1<<2) // a long + + +// defaults for clientinfo messages +#define DEFAULT_VIEWHEIGHT 22 + + +// game types sent by serverinfo +// these determine which intermission screen plays +#define GAME_COOP 0 +#define GAME_DEATHMATCH 1 + +//================== +// note that there are some defs.qc that mirror to these numbers +// also related to svc_strings[] in cl_parse +//================== + +// +// server to client +// +#define svc_bad 0 +#define svc_nop 1 +#define svc_disconnect 2 +#define svc_updatestat 3 // [byte] [long] +#define svc_version 4 // [long] server version +#define svc_setview 5 // [short] entity number +#define svc_sound 6 // +#define svc_time 7 // [float] server time +#define svc_print 8 // [string] null terminated string +#define svc_stufftext 9 // [string] stuffed into client's console buffer + // the string should be \n terminated +#define svc_setangle 10 // [angle3] set the view angle to this absolute value + +#define svc_serverinfo 11 // [long] version + // [string] signon string + // [string]..[0]model cache + // [string]...[0]sounds cache +#define svc_lightstyle 12 // [byte] [string] +#define svc_updatename 13 // [byte] [string] +#define svc_updatefrags 14 // [byte] [short] +#define svc_clientdata 15 // +#define svc_stopsound 16 // +#define svc_updatecolors 17 // [byte] [byte] +#define svc_particle 18 // [vec3] +#define svc_damage 19 + +#define svc_spawnstatic 20 +// svc_spawnbinary 21 +#define svc_spawnbaseline 22 + +#define svc_temp_entity 23 + +#define svc_setpause 24 // [byte] on / off +#define svc_signonnum 25 // [byte] used for the signon sequence + +#define svc_centerprint 26 // [string] to put in center of the screen + +#define svc_killedmonster 27 +#define svc_foundsecret 28 + +#define svc_spawnstaticsound 29 // [coord3] [byte] samp [byte] vol [byte] aten + +#define svc_intermission 30 // [string] music +#define svc_finale 31 // [string] music [string] text + +#define svc_cdtrack 32 // [byte] track [byte] looptrack +#define svc_sellscreen 33 + +#define svc_cutscene 34 + +// +// client to server +// +#define clc_bad 0 +#define clc_nop 1 +#define clc_disconnect 2 +#define clc_move 3 // [usercmd_t] +#define clc_stringcmd 4 // [string] message + + +// +// temp entity events +// +#define TE_SPIKE 0 +#define TE_SUPERSPIKE 1 +#define TE_GUNSHOT 2 +#define TE_EXPLOSION 3 +#define TE_TAREXPLOSION 4 +#define TE_LIGHTNING1 5 +#define TE_LIGHTNING2 6 +#define TE_WIZSPIKE 7 +#define TE_KNIGHTSPIKE 8 +#define TE_LIGHTNING3 9 +#define TE_LAVASPLASH 10 +#define TE_TELEPORT 11 +#define TE_EXPLOSION2 12 + +// PGM 01/21/97 +#define TE_BEAM 13 +// PGM 01/21/97 + +#ifdef QUAKE2 +#define TE_IMPLOSION 14 +#define TE_RAILTRAIL 15 +#endif diff --git a/project/jni/application/quake/source/quakedef.h b/project/jni/application/quake/source/quakedef.h new file mode 100644 index 000000000..15d38981d --- /dev/null +++ b/project/jni/application/quake/source/quakedef.h @@ -0,0 +1,423 @@ +#ifndef _QUAKEDEF_H +#define _QUAKEDEF_H + +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// quakedef.h -- primary header for client + +//#define GLTEST // experimental stuff + + +//#define GP32_DEBUGGING 1 + +//#define USEFPM 1 + +//#if(GP32_DEBUGGING==0) +//#define _GpError(a,b) +//#else +//extern char gpstr[1024]; +//#endif + + + +#define USE_PQ_OPT1 //Uses the fixed point R_EmitEdge_fxp function. +#define USE_PQ_OPT2 +//#define USE_PQ_OPT3 //In progress, don't use. +#define USE_PQ_OPT4 //Uses the fixed point D_PolysetCalcGradients function. +#define USE_PQ_OPT5 //Uses the fixed point D_DrawSpans8 (partially from Jacco Biker) + +#define MIN_VID_HEIGHT 180 + +#define SDL 1 + +#define QUAKE_GAME // as opposed to utilities + +#define GP2X_VERSION 1.02 +#define VERSION 0.01 +#define GLQUAKE_VERSION 1.00 +#define D3DQUAKE_VERSION 0.01 +#define WINQUAKE_VERSION 0.996 +#define LINUX_VERSION 1.30 +#define X11_VERSION 1.10 +#define POCKETQUAKE_VERSION 0.062 + +// Yoda +#ifdef SHx +#define DISABLE_OPTIMIZATION optimize("g",off) +#define ENABLE_OPTIMIZATION optimize("g",on) +#else +#define DISABLE_OPTIMIZATION +#define ENABLE_OPTIMIZATION +#endif + +typedef signed long long int __int64; +typedef unsigned short WORD; +typedef unsigned int DWORD; +typedef unsigned int * PDWORD; + +//define PARANOID // speed sapping error checking + +#ifdef QUAKE2 +#define GAMENAME "id1" // directory to look in by default +#else +#define GAMENAME "id1" +#endif + +#include + +#include +#include +#include + +#include +#include + +#include + +#if defined(_WIN32) && !defined(WINDED) + +#if defined(_M_IX86) +#define __i386__ 1 +#endif + +void VID_LockBuffer (void); +void VID_UnlockBuffer (void); + +#else + +#define VID_LockBuffer() +#define VID_UnlockBuffer() + +#endif + +//#if defined __i386__ // && !defined __sun__ +//#define id386 1 +//#else +#define id386 0 +//#endif + +#if id386 +#define UNALIGNED_OK 1 // set to 0 if unaligned accesses are not supported +#else +#define UNALIGNED_OK 0 +#endif + +// !!! if this is changed, it must be changed in d_ifacea.h too !!! +#define CACHE_SIZE 32 // used to align key data structures + +#define UNUSED(x) (x = x) // for pesky compiler / lint warnings + +#define MINIMUM_MEMORY 0x550000 +#define MINIMUM_MEMORY_LEVELPAK (MINIMUM_MEMORY + 0x100000) + +#define MAX_NUM_ARGVS 50 + +// up / down +#define PITCH 0 + +// left / right +#define YAW 1 + +// fall over +#define ROLL 2 + + +#define MAX_QPATH 128 // max length of a quake game pathname +#define MAX_OSPATH 512 // max length of a filesystem pathname + +#define ON_EPSILON 0.1 // point on plane side epsilon + +#define MAX_MSGLEN 8000 // max length of a reliable message +#define MAX_DATAGRAM 1024 // max length of unreliable message + +// +// per-level limits +// +#define MAX_EDICTS 600 // FIXME: ouch! ouch! ouch! +#define MAX_LIGHTSTYLES 64 +#define MAX_MODELS 256 // these are sent over the net as bytes +#define MAX_SOUNDS 256 // so they cannot be blindly increased + +#define SAVEGAME_COMMENT_LENGTH 39 + +#define MAX_STYLESTRING 64 + +// +// stats are integers communicated to the client by the server +// +#define MAX_CL_STATS 32 +#define STAT_HEALTH 0 +#define STAT_FRAGS 1 +#define STAT_WEAPON 2 +#define STAT_AMMO 3 +#define STAT_ARMOR 4 +#define STAT_WEAPONFRAME 5 +#define STAT_SHELLS 6 +#define STAT_NAILS 7 +#define STAT_ROCKETS 8 +#define STAT_CELLS 9 +#define STAT_ACTIVEWEAPON 10 +#define STAT_TOTALSECRETS 11 +#define STAT_TOTALMONSTERS 12 +#define STAT_SECRETS 13 // bumped on client side by svc_foundsecret +#define STAT_MONSTERS 14 // bumped by svc_killedmonster + +// stock defines + +#define IT_SHOTGUN 1 +#define IT_SUPER_SHOTGUN 2 +#define IT_NAILGUN 4 +#define IT_SUPER_NAILGUN 8 +#define IT_GRENADE_LAUNCHER 16 +#define IT_ROCKET_LAUNCHER 32 +#define IT_LIGHTNING 64 +#define IT_SUPER_LIGHTNING 128 +#define IT_SHELLS 256 +#define IT_NAILS 512 +#define IT_ROCKETS 1024 +#define IT_CELLS 2048 +#define IT_AXE 4096 +#define IT_ARMOR1 8192 +#define IT_ARMOR2 16384 +#define IT_ARMOR3 32768 +#define IT_SUPERHEALTH 65536 +#define IT_KEY1 131072 +#define IT_KEY2 262144 +#define IT_INVISIBILITY 524288 +#define IT_INVULNERABILITY 1048576 +#define IT_SUIT 2097152 +#define IT_QUAD 4194304 +#define IT_SIGIL1 (1<<28) +#define IT_SIGIL2 (1<<29) +#define IT_SIGIL3 (1<<30) +#define IT_SIGIL4 (1<<31) + +//=========================================== +//rogue changed and added defines + +#define RIT_SHELLS 128 +#define RIT_NAILS 256 +#define RIT_ROCKETS 512 +#define RIT_CELLS 1024 +#define RIT_AXE 2048 +#define RIT_LAVA_NAILGUN 4096 +#define RIT_LAVA_SUPER_NAILGUN 8192 +#define RIT_MULTI_GRENADE 16384 +#define RIT_MULTI_ROCKET 32768 +#define RIT_PLASMA_GUN 65536 +#define RIT_ARMOR1 8388608 +#define RIT_ARMOR2 16777216 +#define RIT_ARMOR3 33554432 +#define RIT_LAVA_NAILS 67108864 +#define RIT_PLASMA_AMMO 134217728 +#define RIT_MULTI_ROCKETS 268435456 +#define RIT_SHIELD 536870912 +#define RIT_ANTIGRAV 1073741824 +#define RIT_SUPERHEALTH 2147483648 + +//MED 01/04/97 added hipnotic defines +//=========================================== +//hipnotic added defines +#define HIT_PROXIMITY_GUN_BIT 16 +#define HIT_MJOLNIR_BIT 7 +#define HIT_LASER_CANNON_BIT 23 +#define HIT_PROXIMITY_GUN (1<v[1] >= pfv1->v[1]) + { + scale = (ALIAS_Z_CLIP_PLANE - pav0->fv[2]) / + (pav1->fv[2] - pav0->fv[2]); + + avout.fv[0] = pav0->fv[0] + (pav1->fv[0] - pav0->fv[0]) * scale; + avout.fv[1] = pav0->fv[1] + (pav1->fv[1] - pav0->fv[1]) * scale; + avout.fv[2] = ALIAS_Z_CLIP_PLANE; + + out->v[2] = pfv0->v[2] + (int)((pfv1->v[2] - pfv0->v[2]) * scale); + out->v[3] = pfv0->v[3] + (int)((pfv1->v[3] - pfv0->v[3]) * scale); + out->v[4] = pfv0->v[4] + (int)((pfv1->v[4] - pfv0->v[4]) * scale); + } + else + { + scale = (ALIAS_Z_CLIP_PLANE - pav1->fv[2]) / + (pav0->fv[2] - pav1->fv[2]); + + avout.fv[0] = pav1->fv[0] + (int)((pav0->fv[0] - pav1->fv[0]) * scale); + avout.fv[1] = pav1->fv[1] + (int)((pav0->fv[1] - pav1->fv[1]) * scale); + avout.fv[2] = ALIAS_Z_CLIP_PLANE; + + out->v[2] = pfv1->v[2] + (int)((pfv0->v[2] - pfv1->v[2]) * scale); + out->v[3] = pfv1->v[3] + (int)((pfv0->v[3] - pfv1->v[3]) * scale); + out->v[4] = pfv1->v[4] + (int)((pfv0->v[4] - pfv1->v[4]) * scale); + } + + R_AliasProjectFinalVert (out, &avout); + + if (out->v[0] < r_refdef.aliasvrect.x) + out->flags |= ALIAS_LEFT_CLIP; + if (out->v[1] < r_refdef.aliasvrect.y) + out->flags |= ALIAS_TOP_CLIP; + if (out->v[0] > r_refdef.aliasvrectright) + out->flags |= ALIAS_RIGHT_CLIP; + if (out->v[1] > r_refdef.aliasvrectbottom) + out->flags |= ALIAS_BOTTOM_CLIP; +} + +#ifdef USEFPM +void R_Alias_clip_z_FPM (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) +{ + fixedpoint_t scale; + auxvert_FPM_t *pav0, *pav1, avout; + + pav0 = avFPM[pfv0 - &fv[0][0]]; + pav1 = avFPM[pfv1 - &fv[0][0]]; + + if (pfv0->v[1] >= pfv1->v[1]) + { + scale = FPM_DIV(FPM_SUB(ALIAS_Z_CLIP_PLANE_FPM, pav0->fv[2]), + FPM_SUB(pav1->fv[2], pav0->fv[2])); + + avout.fv[0] = FPM_TOLONG(FPM_ADD(pav0->fv[0], FPM_MUL(FPM_SUB(pav1->fv[0], pav0->fv[0]),scale))); + avout.fv[1] = FPM_TOLONG(FPM_ADD(pav0->fv[1], FPM_MUL(FPM_SUB(pav1->fv[1], pav0->fv[1]), scale))); + avout.fv[2] = ALIAS_Z_CLIP_PLANE; + + out->v[2] = pfv0->v[2] + FPM_TOLONG(FPM_MUL(FPM_FROMLONG(pfv1->v[2] - pfv0->v[2]), scale)); + out->v[3] = pfv0->v[3] + FPM_TOLONG(FPM_MUL(FPM_FROMLONG(pfv1->v[3] - pfv0->v[3]), scale)); + out->v[4] = pfv0->v[4] + FPM_TOLONG(FPM_MUL(FPM_FROMLONG(pfv1->v[4] - pfv0->v[4]), scale)); + } + else + { + scale = FPM_DIV(FPM_SUB(ALIAS_Z_CLIP_PLANE_FPM, pav1->fv[2]), + FPM_SUB(pav0->fv[2], pav1->fv[2])); + + avout.fv[0] = FPM_TOLONG(FPM_ADD(pav1->fv[0], FPM_MUL(FPM_SUB(pav0->fv[0], pav1->fv[0]),scale))); + avout.fv[1] = FPM_TOLONG(FPM_ADD(pav1->fv[1], FPM_MUL(FPM_SUB(pav0->fv[1], pav1->fv[1]), scale))); + avout.fv[2] = ALIAS_Z_CLIP_PLANE; + + out->v[2] = pfv1->v[2] + FPM_TOLONG(FPM_MUL(FPM_FROMLONG((pfv0->v[2] - pfv1->v[2])), scale)); + out->v[3] = pfv1->v[3] + FPM_TOLONG(FPM_MUL(FPM_FROMLONG(pfv0->v[3] - pfv1->v[3]), scale)); + out->v[4] = pfv1->v[4] + FPM_TOLONG(FPM_MUL(FPM_FROMLONG(pfv0->v[4] - pfv1->v[4]), scale)); + } + + R_AliasProjectFinalVertFPM (out, &avout); + + if (out->v[0] < r_refdefFPM.aliasvrect.x) + out->flags |= ALIAS_LEFT_CLIP; + if (out->v[1] < r_refdefFPM.aliasvrect.y) + out->flags |= ALIAS_TOP_CLIP; + if (out->v[0] > r_refdefFPM.aliasvrectright) + out->flags |= ALIAS_RIGHT_CLIP; + if (out->v[1] > r_refdefFPM.aliasvrectbottom) + out->flags |= ALIAS_BOTTOM_CLIP; +} +#endif //USEFPM + +#if !id386 + +void R_Alias_clip_left (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) +{ + float scale; + int i; + + if (pfv0->v[1] >= pfv1->v[1]) + { + scale = (float)(r_refdef.aliasvrect.x - pfv0->v[0]) / + (pfv1->v[0] - pfv0->v[0]); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv0->v[i] + (int)((pfv1->v[i] - pfv0->v[i])*scale + 0.5); + } + else + { + scale = (float)(r_refdef.aliasvrect.x - pfv1->v[0]) / + (pfv0->v[0] - pfv1->v[0]); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv1->v[i] + (int)((pfv0->v[i] - pfv1->v[i])*scale + 0.5); + } +} + +#ifdef USEFPM +void R_Alias_clip_leftFPM (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) +{ + fixedpoint_t scale; + int i; + + if (pfv0->v[1] >= pfv1->v[1]) + { + scale = FPM_DIV(FPM_FROMLONG(r_refdef.aliasvrect.x - pfv0->v[0]), + FPM_FROMLONG(pfv1->v[0] - pfv0->v[0])); + for (i=0 ; i<6 ; i++) + out->v[i] = FPM_ADD3(FPM_FROMLONG(pfv0->v[i]), FPM_MUL(FPM_FROMLONG(pfv1->v[i] - pfv0->v[i]),scale), FPM_FROMFLOAT(0.5)); + } + else + { + scale = FPM_DIV(FPM_FROMLONG(r_refdef.aliasvrect.x - pfv1->v[0]), + FPM_FROMLONG(pfv0->v[0] - pfv1->v[0])); + for (i=0 ; i<6 ; i++) + out->v[i] = FPM_ADD3(FPM_FROMLONG(pfv1->v[i]), FPM_MUL(FPM_FROMLONG(pfv0->v[i] - pfv1->v[i]),scale), FPM_FROMFLOAT(0.5)); + } +} +#endif //USEFPM + +void R_Alias_clip_right (finalvert_t *pfv0, finalvert_t *pfv1, + finalvert_t *out) +{ + float scale; + int i; + + if (pfv0->v[1] >= pfv1->v[1]) + { + scale = (float)(r_refdef.aliasvrectright - pfv0->v[0]) / + (pfv1->v[0] - pfv0->v[0]); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv0->v[i] + (int)((pfv1->v[i] - pfv0->v[i])*scale + 0.5); + } + else + { + scale = (float)(r_refdef.aliasvrectright - pfv1->v[0]) / + (pfv0->v[0] - pfv1->v[0]); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv1->v[i] + (int)((pfv0->v[i] - pfv1->v[i])*scale + 0.5); + } +} + +#ifdef USEFPM +void R_Alias_clip_rightFPM (finalvert_t *pfv0, finalvert_t *pfv1, + finalvert_t *out) +{ + fixedpoint_t scale; + int i; + + if (pfv0->v[1] >= pfv1->v[1]) + { + scale = FPM_DIV(FPM_FROMLONG(r_refdefFPM.aliasvrectright - pfv0->v[0]), + FPM_FROMLONG(pfv1->v[0] - pfv0->v[0])); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv0->v[i] + FPM_TOLONG(FPM_ADD(FPM_MUL(FPM_FROMLONG(pfv1->v[i] - pfv0->v[i]),scale), FPM_FROMFLOAT(0.5))); + } + else + { + scale = FPM_DIV(FPM_FROMLONG(r_refdefFPM.aliasvrectright - pfv1->v[0]), + FPM_FROMLONG(pfv0->v[0] - pfv1->v[0])); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv1->v[i] + FPM_TOLONG(FPM_ADD(FPM_MUL(FPM_FROMLONG(pfv0->v[i] - pfv1->v[i]),scale), FPM_FROMFLOAT(0.5))); + } +} +#endif //USEFPM + +void R_Alias_clip_top (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) +{ + float scale; + int i; + + if (pfv0->v[1] >= pfv1->v[1]) + { + scale = (float)(r_refdef.aliasvrect.y - pfv0->v[1]) / + (pfv1->v[1] - pfv0->v[1]); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv0->v[i] + (int)((pfv1->v[i] - pfv0->v[i])*scale + 0.5); + } + else + { + scale = (float)(r_refdef.aliasvrect.y - pfv1->v[1]) / + (pfv0->v[1] - pfv1->v[1]); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv1->v[i] + (int)((pfv0->v[i] - pfv1->v[i])*scale + 0.5); + } +} + +#ifdef USEFPM +void R_Alias_clip_topFPM (finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) +{ + fixedpoint_t scale; + int i; + + if (pfv0->v[1] >= pfv1->v[1]) + { + scale = FPM_DIV(FPM_FROMLONG(r_refdefFPM.aliasvrect.y - pfv0->v[1]), + FPM_FROMLONG(pfv1->v[1] - pfv0->v[1])); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv0->v[i] + FPM_TOLONG(FPM_ADD(FPM_MUL(FPM_FROMLONG(pfv1->v[i] - pfv0->v[i]),scale), FPM_FROMFLOAT(0.5))); + } + else + { + scale = FPM_DIV(FPM_FROMLONG(r_refdefFPM.aliasvrect.y - pfv1->v[1]), + FPM_FROMLONG(pfv0->v[1] - pfv1->v[1])); + for (i=0 ; i<6 ; i++) + out->v[i] = pfv1->v[i] + FPM_TOLONG(FPM_ADD(FPM_MUL(FPM_FROMLONG(pfv0->v[i] - pfv1->v[i]),scale), FPM_FROMFLOAT(0.5))); + } +} +#endif //USEFPM + +void R_Alias_clip_bottom (finalvert_t *pfv0, finalvert_t *pfv1, + finalvert_t *out) +{ + float scale; + int i; + + if (pfv0->v[1] >= pfv1->v[1]) + { + scale = (float)(r_refdef.aliasvrectbottom - pfv0->v[1]) / + (pfv1->v[1] - pfv0->v[1]); + + for (i=0 ; i<6 ; i++) + out->v[i] = pfv0->v[i] + (int)((pfv1->v[i] - pfv0->v[i])*scale + 0.5); + } + else + { + scale = (float)(r_refdef.aliasvrectbottom - pfv1->v[1]) / + (pfv0->v[1] - pfv1->v[1]); + + for (i=0 ; i<6 ; i++) + out->v[i] = pfv1->v[i] + (int)((pfv0->v[i] - pfv1->v[i])*scale + 0.5); + } +} + +#ifdef USEFPM +void R_Alias_clip_bottomFPM (finalvert_t *pfv0, finalvert_t *pfv1, + finalvert_t *out) +{ + fixedpoint_t scale; + int i; + + if (pfv0->v[1] >= pfv1->v[1]) + { + scale = FPM_DIV(FPM_FROMLONG(r_refdefFPM.aliasvrectbottom - pfv0->v[1]), + FPM_FROMLONG(pfv1->v[1] - pfv0->v[1])); + + for (i=0 ; i<6 ; i++) + out->v[i] = pfv0->v[i] + FPM_TOLONG(FPM_ADD(FPM_MUL(FPM_FROMLONG(pfv1->v[i] - pfv0->v[i]),scale), FPM_FROMFLOAT(0.5))); + } + else + { + scale = FPM_DIV(FPM_FROMLONG(r_refdefFPM.aliasvrectbottom - pfv1->v[1]), + FPM_FROMLONG(pfv0->v[1] - pfv1->v[1])); + + for (i=0 ; i<6 ; i++) + out->v[i] = pfv1->v[i] + FPM_TOLONG(FPM_ADD(FPM_MUL(FPM_FROMLONG(pfv0->v[i] - pfv1->v[i]),scale), FPM_FROMFLOAT(0.5))); + } +} +#endif //USEFPM +#endif + + +int R_AliasClip (finalvert_t *in, finalvert_t *out, int flag, int count, + void(*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) ) +{ + int i,j,k; + int flags, oldflags; + + j = count-1; + k = 0; + for (i=0 ; i r_refdef.aliasvrectright) + out[k].flags |= ALIAS_RIGHT_CLIP; + if (out[k].v[1] > r_refdef.aliasvrectbottom) + out[k].flags |= ALIAS_BOTTOM_CLIP; + k++; + } + if (!flags) + { + out[k] = in[i]; + k++; + } + } + + return k; +} + +#ifdef USEFPM +int R_AliasClipFPM (finalvert_t *in, finalvert_t *out, int flag, int count, + void(*clip)(finalvert_t *pfv0, finalvert_t *pfv1, finalvert_t *out) ) +{ + int i,j,k; + int flags, oldflags; + + j = count-1; + k = 0; + for (i=0 ; i r_refdefFPM.aliasvrectright) + out[k].flags |= ALIAS_RIGHT_CLIP; + if (out[k].v[1] > r_refdefFPM.aliasvrectbottom) + out[k].flags |= ALIAS_BOTTOM_CLIP; + k++; + } + if (!flags) + { + out[k] = in[i]; + k++; + } + } + + return k; +} +#endif //USEFPM +/* +================ +R_AliasClipTriangle +================ +*/ +void R_AliasClipTriangle (mtriangle_t *ptri) +{ + int i, k, pingpong; + mtriangle_t mtri; + unsigned clipflags; + +// copy vertexes and fix seam texture coordinates + if (ptri->facesfront) + { + fv[0][0] = pfinalverts[ptri->vertindex[0]]; + fv[0][1] = pfinalverts[ptri->vertindex[1]]; + fv[0][2] = pfinalverts[ptri->vertindex[2]]; + } + else + { + for (i=0 ; i<3 ; i++) + { + fv[0][i] = pfinalverts[ptri->vertindex[i]]; + + if (!ptri->facesfront && (fv[0][i].flags & ALIAS_ONSEAM) ) + fv[0][i].v[2] += r_affinetridesc.seamfixupX16; + } + } + +// clip + clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags; + + if (clipflags & ALIAS_Z_CLIP) + { + for (i=0 ; i<3 ; i++) + av[i] = pauxverts[ptri->vertindex[i]]; + + k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z); + if (k == 0) + return; + + pingpong = 1; + clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags; + } + else + { + pingpong = 0; + k = 3; + } + + if (clipflags & ALIAS_LEFT_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_LEFT_CLIP, k, R_Alias_clip_left); + if (k == 0) + return; + + pingpong ^= 1; + } + + if (clipflags & ALIAS_RIGHT_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_RIGHT_CLIP, k, R_Alias_clip_right); + if (k == 0) + return; + + pingpong ^= 1; + } + + if (clipflags & ALIAS_BOTTOM_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom); + if (k == 0) + return; + + pingpong ^= 1; + } + + if (clipflags & ALIAS_TOP_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_TOP_CLIP, k, R_Alias_clip_top); + if (k == 0) + return; + + pingpong ^= 1; + } + + for (i=0 ; i r_refdef.aliasvrectright) + fv[pingpong][i].v[0] = r_refdef.aliasvrectright; + + if (fv[pingpong][i].v[1] < r_refdef.aliasvrect.y) + fv[pingpong][i].v[1] = r_refdef.aliasvrect.y; + else if (fv[pingpong][i].v[1] > r_refdef.aliasvrectbottom) + fv[pingpong][i].v[1] = r_refdef.aliasvrectbottom; + + fv[pingpong][i].flags = 0; + } + +// draw triangles + mtri.facesfront = ptri->facesfront; + r_affinetridesc.ptriangles = &mtri; + r_affinetridesc.pfinalverts = fv[pingpong]; + +// FIXME: do all at once as trifan? + mtri.vertindex[0] = 0; + for (i=1 ; ifacesfront) + { + fv[0][0] = pfinalverts[ptri->vertindex[0]]; + fv[0][1] = pfinalverts[ptri->vertindex[1]]; + fv[0][2] = pfinalverts[ptri->vertindex[2]]; + } + else + { + for (i=0 ; i<3 ; i++) + { + fv[0][i] = pfinalverts[ptri->vertindex[i]]; + + if (!ptri->facesfront && (fv[0][i].flags & ALIAS_ONSEAM) ) + fv[0][i].v[2] += r_affinetridesc.seamfixupX16; + } + } + +// clip + clipflags = fv[0][0].flags | fv[0][1].flags | fv[0][2].flags; + + if (clipflags & ALIAS_Z_CLIP) + { + for (i=0 ; i<3 ; i++) + avFPM[i] = &pauxvertsFPM[ptri->vertindex[i]]; + + k = R_AliasClip (fv[0], fv[1], ALIAS_Z_CLIP, 3, R_Alias_clip_z_FPM); + if (k == 0) + return; + + pingpong = 1; + clipflags = fv[1][0].flags | fv[1][1].flags | fv[1][2].flags; + } + else + { + pingpong = 0; + k = 3; + } + + if (clipflags & ALIAS_LEFT_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_LEFT_CLIP, k, R_Alias_clip_left); + if (k == 0) + return; + + pingpong ^= 1; + } + + if (clipflags & ALIAS_RIGHT_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_RIGHT_CLIP, k, R_Alias_clip_right); + if (k == 0) + return; + + pingpong ^= 1; + } + + if (clipflags & ALIAS_BOTTOM_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_BOTTOM_CLIP, k, R_Alias_clip_bottom); + if (k == 0) + return; + + pingpong ^= 1; + } + + if (clipflags & ALIAS_TOP_CLIP) + { + k = R_AliasClip (fv[pingpong], fv[pingpong ^ 1], + ALIAS_TOP_CLIP, k, R_Alias_clip_top); + if (k == 0) + return; + + pingpong ^= 1; + } + + for (i=0 ; i r_refdefFPM.aliasvrectright) + fv[pingpong][i].v[0] = r_refdefFPM.aliasvrectright; + + if (fv[pingpong][i].v[1] < r_refdefFPM.aliasvrect.y) + fv[pingpong][i].v[1] = r_refdefFPM.aliasvrect.y; + else if (fv[pingpong][i].v[1] > r_refdefFPM.aliasvrectbottom) + fv[pingpong][i].v[1] = r_refdefFPM.aliasvrectbottom; + + fv[pingpong][i].flags = 0; + } + +// draw triangles + mtri.facesfront = ptri->facesfront; + r_affinetridesc.ptriangles = &mtri; + r_affinetridesc.pfinalverts = fv[pingpong]; + +// FIXME: do all at once as trifan? + mtri.vertindex[0] = 0; + for (i=1 ; itrivial_accept = 0; + pmodel = currententity->model; + pahdr = Mod_Extradata (pmodel); + pmdl = (mdl_t *)((byte *)pahdr + pahdr->model); + + R_AliasSetUpTransform (0); + +// construct the base bounding box for this frame + frame = currententity->frame; +// TODO: don't repeat this check when drawing? + if ((frame >= pmdl->numframes) || (frame < 0)) + { + Con_DPrintf ("No such frame %d %s\n", frame, + pmodel->name); + frame = 0; + } + + pframedesc = &pahdr->frames[frame]; + +// x worldspace coordinates + basepts[0][0] = basepts[1][0] = basepts[2][0] = basepts[3][0] = + (float)pframedesc->bboxmin.v[0]; + basepts[4][0] = basepts[5][0] = basepts[6][0] = basepts[7][0] = + (float)pframedesc->bboxmax.v[0]; + +// y worldspace coordinates + basepts[0][1] = basepts[3][1] = basepts[5][1] = basepts[6][1] = + (float)pframedesc->bboxmin.v[1]; + basepts[1][1] = basepts[2][1] = basepts[4][1] = basepts[7][1] = + (float)pframedesc->bboxmax.v[1]; + +// z worldspace coordinates + basepts[0][2] = basepts[1][2] = basepts[4][2] = basepts[5][2] = + (float)pframedesc->bboxmin.v[2]; + basepts[2][2] = basepts[3][2] = basepts[6][2] = basepts[7][2] = + (float)pframedesc->bboxmax.v[2]; + + zclipped = false; + zfullyclipped = true; + + minz = 9999; + for (i=0; i<8 ; i++) + { + R_AliasTransformVector (&basepts[i][0], &viewaux[i].fv[0]); + + if (viewaux[i].fv[2] < ALIAS_Z_CLIP_PLANE) + { + // we must clip points that are closer than the near clip plane + viewpts[i].flags = ALIAS_Z_CLIP; + zclipped = true; + } + else + { + if (viewaux[i].fv[2] < minz) + minz = (int)viewaux[i].fv[2]; + viewpts[i].flags = 0; + zfullyclipped = false; + } + } + + + if (zfullyclipped) + { + return false; // everything was near-z-clipped + } + + numv = 8; + + if (zclipped) + { + // organize points by edges, use edges to get new points (possible trivial + // reject) + for (i=0 ; i<12 ; i++) + { + // edge endpoints + pv0 = &viewpts[aedges[i].index0]; + pv1 = &viewpts[aedges[i].index1]; + pa0 = &viewaux[aedges[i].index0]; + pa1 = &viewaux[aedges[i].index1]; + + // if one end is clipped and the other isn't, make a new point + if (pv0->flags ^ pv1->flags) + { + frac = (ALIAS_Z_CLIP_PLANE - pa0->fv[2]) / + (pa1->fv[2] - pa0->fv[2]); + viewaux[numv].fv[0] = pa0->fv[0] + + (pa1->fv[0] - pa0->fv[0]) * frac; + viewaux[numv].fv[1] = pa0->fv[1] + + (pa1->fv[1] - pa0->fv[1]) * frac; + viewaux[numv].fv[2] = ALIAS_Z_CLIP_PLANE; + viewpts[numv].flags = 0; + numv++; + } + } + } + +// project the vertices that remain after clipping + anyclip = 0; + allclip = ALIAS_XY_CLIP_MASK; + +// TODO: probably should do this loop in ASM, especially if we use floats + for (i=0 ; i r_refdef.fvrectright) + flags |= ALIAS_RIGHT_CLIP; + if (v1 > r_refdef.fvrectbottom) + flags |= ALIAS_BOTTOM_CLIP; + + anyclip |= flags; + allclip &= flags; + } + + if (allclip) + return false; // trivial reject off one side + + currententity->trivial_accept = !anyclip & !zclipped; + + if (currententity->trivial_accept) + { + if (minz > (r_aliastransition + (pmdl->size * r_resfudge))) + { + currententity->trivial_accept |= 2; + } + } + + return true; +} + +#ifdef USEFPM +qboolean R_AliasCheckBBoxFPM (void) +{ + int i, flags, frame, numv; + aliashdr_t *pahdr; + fixedpoint_t zi, basepts[8][3], frac; //v0, v1; + finalvert_t *pv0, *pv1, viewpts[16]; + auxvert_FPM_t *pa0, *pa1, viewaux[16]; + maliasframedesc_t *pframedesc; + qboolean zclipped, zfullyclipped; + unsigned anyclip, allclip; + int minz; + +// expand, rotate, and translate points into worldspace + + currententityFPM->trivial_accept = 0; + pmodelFPM = currententityFPM->model; + pahdr = Mod_ExtradataFPM (pmodelFPM); + pmdlFPM = (mdl_FPM_t *)((byte *)pahdr + pahdr->model); + + R_AliasSetUpTransformFPM (0); + +// construct the base bounding box for this frame + frame = currententityFPM->frame; +// TODO: don't repeat this check when drawing? + if ((frame >= pmdlFPM->numframes) || (frame < 0)) + { + Con_DPrintf ("No such frame %d %s\n", frame, + pmodelFPM->name); + frame = 0; + } + + pframedesc = &pahdr->frames[frame]; + +// x worldspace coordinates + basepts[0][0] = basepts[1][0] = basepts[2][0] = basepts[3][0] = + FPM_FROMLONG(pframedesc->bboxmin.v[0]); + basepts[4][0] = basepts[5][0] = basepts[6][0] = basepts[7][0] = + FPM_FROMLONG(pframedesc->bboxmax.v[0]); + +// y worldspace coordinates + basepts[0][1] = basepts[3][1] = basepts[5][1] = basepts[6][1] = + FPM_FROMLONG(pframedesc->bboxmin.v[1]); + basepts[1][1] = basepts[2][1] = basepts[4][1] = basepts[7][1] = + FPM_FROMLONG(pframedesc->bboxmax.v[1]); + +// z worldspace coordinates + basepts[0][2] = basepts[1][2] = basepts[4][2] = basepts[5][2] = + FPM_FROMLONG(pframedesc->bboxmin.v[2]); + basepts[2][2] = basepts[3][2] = basepts[6][2] = basepts[7][2] = + FPM_FROMLONG(pframedesc->bboxmax.v[2]); + + zclipped = false; + zfullyclipped = true; + + minz = 9999; + for (i=0; i<8 ; i++) + { + R_AliasTransformVectorFPM (&basepts[i][0], &viewaux[i].fv[0]); + + if (viewaux[i].fv[2] < ALIAS_Z_CLIP_PLANE) + { + // we must clip points that are closer than the near clip plane + viewpts[i].flags = ALIAS_Z_CLIP; + zclipped = true; + } + else + { + if (viewaux[i].fv[2] < minz) + minz = FPM_TOLONG(viewaux[i].fv[2]); + viewpts[i].flags = 0; + zfullyclipped = false; + } + } + + + if (zfullyclipped) + { + return false; // everything was near-z-clipped + } + + numv = 8; + + if (zclipped) + { + // organize points by edges, use edges to get new points (possible trivial + // reject) + for (i=0 ; i<12 ; i++) + { + // edge endpoints + pv0 = &viewpts[aedges[i].index0]; + pv1 = &viewpts[aedges[i].index1]; + pa0 = &viewaux[aedges[i].index0]; + pa1 = &viewaux[aedges[i].index1]; + + // if one end is clipped and the other isn't, make a new point + if (pv0->flags ^ pv1->flags) + { + frac = FPM_DIV(FPM_SUB(ALIAS_Z_CLIP_PLANE_FPM, pa0->fv[2]), + FPM_SUB(pa1->fv[2], pa0->fv[2])); + viewaux[numv].fv[0] = FPM_ADD(pa0->fv[0], + FPM_MUL(FPM_SUB(pa1->fv[0], pa0->fv[0]), frac)); + viewaux[numv].fv[1] = FPM_ADD(pa0->fv[1], + FPM_MUL(FPM_SUB(pa1->fv[1], pa0->fv[1]), frac)); + viewaux[numv].fv[2] = ALIAS_Z_CLIP_PLANE_FPM; + viewpts[numv].flags = 0; + numv++; + } + } + } + +// project the vertices that remain after clipping + anyclip = 0; + allclip = ALIAS_XY_CLIP_MASK; + +// TODO: probably should do this loop in ASM, especially if we use floats + for (i=0 ; i>=16; + i2=zi; + i2<<=16; + i1*=i2; + i1>>=16; + i2=xcenterFPM; + i2<<=16; + i1+=i2; + if (i1 < r_refdefFPM.fvrectx) + flags |= ALIAS_LEFT_CLIP; + if (i1 > r_refdefFPM.fvrectright) + flags |= ALIAS_RIGHT_CLIP; + + //v0 = FPM_ADD(FPM_MUL(FPM_MUL(viewaux[i].fv[0], xscaleFPM), zi), xcenterFPM); + + i1=viewaux[i].fv[1]; + i1<<=16; + i2=yscaleFPM; + i2<<=16; + i1*=i2; + i1>>=16; + i2=zi; + i2<<=16; + i1*=i2; + i1>>=16; + i2=ycenterFPM; + i2<<=16; + i1+=i2; + + if (i1 < r_refdefFPM.fvrecty) + flags |= ALIAS_TOP_CLIP; + if (i1 > r_refdefFPM.fvrectbottom) + flags |= ALIAS_BOTTOM_CLIP; + + //v1 = FPM_ADD(FPM_MUL(FPM_MUL(viewaux[i].fv[1], yscaleFPM), zi), ycenterFPM); + + flags = 0; + +// if (v0 < r_refdefFPM.fvrectx) +// flags |= ALIAS_LEFT_CLIP; +// if (v1 < r_refdefFPM.fvrecty) +// flags |= ALIAS_TOP_CLIP; +// if (v0 > r_refdefFPM.fvrectright) +// flags |= ALIAS_RIGHT_CLIP; +// if (v1 > r_refdefFPM.fvrectbottom) +// flags |= ALIAS_BOTTOM_CLIP; + + anyclip |= flags; + allclip &= flags; + } + + if (allclip) + return false; // trivial reject off one side + + currententityFPM->trivial_accept = !anyclip & !zclipped; + + if (currententityFPM->trivial_accept) + { + if (minz > FPM_TOLONG(FPM_ADD(r_aliastransitionFPM, FPM_MUL(pmdlFPM->size, r_resfudgeFPM)))) + { + currententityFPM->trivial_accept |= 2; + } + } + + return true; +} +#endif //USEFPM + +/* +================ +R_AliasTransformVector +================ +*/ +void R_AliasTransformVector (vec3_t in, vec3_t out) +{ + out[0] = DotProduct(in, aliastransform[0]) + aliastransform[0][3]; + out[1] = DotProduct(in, aliastransform[1]) + aliastransform[1][3]; + out[2] = DotProduct(in, aliastransform[2]) + aliastransform[2][3]; +} +/* +void R_AliasTransformVectorFPM (vec3_FPM_t in, vec3_FPM_t out) +{ + out[0] = fpm_Add(DotProductFPM(in, aliastransformFPM[0]), aliastransformFPM[0][3]); + out[1] = fpm_Add(DotProductFPM(in, aliastransformFPM[1]), aliastransformFPM[1][3]); + out[2] = fpm_Add(DotProductFPM(in, aliastransformFPM[2]), aliastransformFPM[2][3]); +} +*/ + +#ifdef USEFPM +void R_AliasTransformVectorFPM (vec3_FPM_t in, vec3_FPM_t out) +{ + out[0] = fpm_Add(DotProduct8_24FPM(aliastransformFPM[0], in), (fixedpoint_t)aliastransformFPM[0][3]); + out[1] = fpm_Add(DotProduct8_24FPM(aliastransformFPM[1], in), (fixedpoint_t)aliastransformFPM[1][3]); + out[2] = fpm_Add(DotProduct8_24FPM(aliastransformFPM[2], in), (fixedpoint_t)aliastransformFPM[2][3]); +} +#endif //USEFPM + +/* +================ +R_AliasPreparePoints + +General clipped case +================ +*/ + +void R_AliasPreparePoints (void) +{ + int i; + stvert_t *pstverts; + finalvert_t *fv; + auxvert_t *av; + mtriangle_t *ptri; + finalvert_t *pfv[3]; + + pstverts = (stvert_t *)((byte *)paliashdr + paliashdr->stverts); + r_anumverts = pmdl->numverts; + fv = pfinalverts; + av = pauxverts; + + for (i=0 ; ifv[2] < ALIAS_Z_CLIP_PLANE) + fv->flags |= ALIAS_Z_CLIP; + else + { + R_AliasProjectFinalVert (fv, av); + + if (fv->v[0] < r_refdef.aliasvrect.x) + fv->flags |= ALIAS_LEFT_CLIP; + if (fv->v[1] < r_refdef.aliasvrect.y) + fv->flags |= ALIAS_TOP_CLIP; + if (fv->v[0] > r_refdef.aliasvrectright) + fv->flags |= ALIAS_RIGHT_CLIP; + if (fv->v[1] > r_refdef.aliasvrectbottom) + fv->flags |= ALIAS_BOTTOM_CLIP; + } + } + +// +// clip and draw all triangles +// + r_affinetridesc.numtriangles = 1; + + ptri = (mtriangle_t *)((byte *)paliashdr + paliashdr->triangles); + for (i=0 ; inumtris ; i++, ptri++) + { + pfv[0] = &pfinalverts[ptri->vertindex[0]]; + pfv[1] = &pfinalverts[ptri->vertindex[1]]; + pfv[2] = &pfinalverts[ptri->vertindex[2]]; + + if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags & (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP) ) + continue; // completely clipped + + if ( ! ( (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) & + (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP) ) ) + { // totally unclipped + r_affinetridesc.pfinalverts = pfinalverts; + r_affinetridesc.ptriangles = ptri; + D_PolysetDraw (); + } + else + { // partially clipped + R_AliasClipTriangle (ptri); + } + } +} + +#ifdef USEFPM +void R_AliasPreparePointsFPM (void) +{ + int i; + stvert_t *pstverts; //Ok, no floats + finalvert_t *fv; //.reserved + auxvert_FPM_t *av; //all floats + mtriangle_t *ptri; //ok + finalvert_t *pfv[3]; //.reserved + + pstverts = (stvert_t *)((byte *)paliashdr + paliashdr->stverts); + r_anumverts = pmdlFPM->numverts; + fv = pfinalverts; + av = pauxvertsFPM; + + for (i=0 ; ifv[2] < ALIAS_Z_CLIP_PLANE_FPM) + fv->flags |= ALIAS_Z_CLIP; + else + { + R_AliasProjectFinalVertFPM (fv, av); + + if (fv->v[0] < r_refdefFPM.aliasvrect.x) + fv->flags |= ALIAS_LEFT_CLIP; + if (fv->v[1] < r_refdefFPM.aliasvrect.y) + fv->flags |= ALIAS_TOP_CLIP; + if (fv->v[0] > r_refdefFPM.aliasvrectright) + fv->flags |= ALIAS_RIGHT_CLIP; + if (fv->v[1] > r_refdefFPM.aliasvrectbottom) + fv->flags |= ALIAS_BOTTOM_CLIP; + } + } + +// +// clip and draw all triangles +// + r_affinetridesc.numtriangles = 1; + + ptri = (mtriangle_t *)((byte *)paliashdr + paliashdr->triangles); + for (i=0 ; inumtris ; i++, ptri++) + { + pfv[0] = &pfinalverts[ptri->vertindex[0]]; + pfv[1] = &pfinalverts[ptri->vertindex[1]]; + pfv[2] = &pfinalverts[ptri->vertindex[2]]; + + if ( pfv[0]->flags & pfv[1]->flags & pfv[2]->flags & (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP) ) + continue; // completely clipped + + if ( ! ( (pfv[0]->flags | pfv[1]->flags | pfv[2]->flags) & + (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP) ) ) + { // totally unclipped + r_affinetridesc.pfinalverts = pfinalverts; + r_affinetridesc.ptriangles = ptri; + D_PolysetDraw (); //TODO: Dan + } + else + { // partially clipped + R_AliasClipTriangleFPM (ptri); + } + } +} +#endif //USEFPM + +/* +================ +R_AliasSetUpTransform +================ +*/ +void R_AliasSetUpTransform (int trivial_accept) +{ + int i; + float rotationmatrix[3][4], t2matrix[3][4]; + static float tmatrix[3][4]; + static float viewmatrix[3][4]; + vec3_t angles; + +// TODO: should really be stored with the entity instead of being reconstructed +// TODO: should use a look-up table +// TODO: could cache lazily, stored in the entity + + angles[ROLL] = currententity->angles[ROLL]; + angles[PITCH] = -currententity->angles[PITCH]; + angles[YAW] = currententity->angles[YAW]; + AngleVectors (angles, alias_forward, alias_right, alias_up); + + tmatrix[0][0] = pmdl->scale[0]; + tmatrix[1][1] = pmdl->scale[1]; + tmatrix[2][2] = pmdl->scale[2]; + + tmatrix[0][3] = pmdl->scale_origin[0]; + tmatrix[1][3] = pmdl->scale_origin[1]; + tmatrix[2][3] = pmdl->scale_origin[2]; + +// TODO: can do this with simple matrix rearrangement + + for (i=0 ; i<3 ; i++) + { + t2matrix[i][0] = alias_forward[i]; + t2matrix[i][1] = -alias_right[i]; + t2matrix[i][2] = alias_up[i]; + } + + t2matrix[0][3] = -modelorg[0]; + t2matrix[1][3] = -modelorg[1]; + t2matrix[2][3] = -modelorg[2]; + +// FIXME: can do more efficiently than full concatenation + R_ConcatTransforms (t2matrix, tmatrix, rotationmatrix); + +// TODO: should be global, set when vright, etc., set + VectorCopy (vright, viewmatrix[0]); + VectorCopy (vup, viewmatrix[1]); + VectorInverse (viewmatrix[1]); + VectorCopy (vpn, viewmatrix[2]); + +// viewmatrix[0][3] = 0; +// viewmatrix[1][3] = 0; +// viewmatrix[2][3] = 0; + + R_ConcatTransforms (viewmatrix, rotationmatrix, aliastransform); + +// do the scaling up of x and y to screen coordinates as part of the transform +// for the unclipped case (it would mess up clipping in the clipped case). +// Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y +// correspondingly so the projected x and y come out right +// FIXME: make this work for clipped case too? + if (trivial_accept) + { + for (i=0 ; i<4 ; i++) + { + aliastransform[0][i] *= aliasxscale * + (((float)1.0) / ((float)0x8000 * 0x10000)); + aliastransform[1][i] *= aliasyscale * + (((float)1.0) / ((float)0x8000 * 0x10000)); + aliastransform[2][i] *= 1.0 / ((float)0x8000 * 0x10000); + + } + } +} + +#ifdef USEFPM +void R_AliasSetUpTransformFPM (int trivial_accept) +{ + int i; + fixedpoint_t rotationmatrix[3][4], t2matrix[3][4]; + static fixedpoint_t tmatrix[3][4]; + static fixedpoint_t viewmatrix[3][4]; + vec3_FPM_t angles; + +// TODO: should really be stored with the entity instead of being reconstructed +// TODO: should use a look-up table +// TODO: could cache lazily, stored in the entity + + angles[ROLL] = currententityFPM->angles[ROLL]; + angles[PITCH] = -currententityFPM->angles[PITCH]; + angles[YAW] = currententityFPM->angles[YAW]; + AngleVectorsFPM (angles, alias_forwardFPM, alias_rightFPM, alias_upFPM); + + tmatrix[0][0] = pmdlFPM->scale[0]; + tmatrix[1][1] = pmdlFPM->scale[1]; + tmatrix[2][2] = pmdlFPM->scale[2]; + + tmatrix[0][3] = pmdlFPM->scale_origin[0]; + tmatrix[1][3] = pmdlFPM->scale_origin[1]; + tmatrix[2][3] = pmdlFPM->scale_origin[2]; + +// TODO: can do this with simple matrix rearrangement + + for (i=0 ; i<3 ; i++) + { + t2matrix[i][0] = alias_forwardFPM[i]; + t2matrix[i][1] = -alias_rightFPM[i]; + t2matrix[i][2] = alias_upFPM[i]; + } + + t2matrix[0][3] = -modelorgFPM[0]; + t2matrix[1][3] = -modelorgFPM[1]; + t2matrix[2][3] = -modelorgFPM[2]; + +// FIXME: can do more efficiently than full concatenation + R_ConcatTransformsFPM (t2matrix, tmatrix, rotationmatrix); + +// TODO: should be global, set when vright, etc., set + VectorCopy (vrightFPM, viewmatrix[0]); + VectorCopy (vupFPM, viewmatrix[1]); + VectorInverseFPM (viewmatrix[1]); + VectorCopy (vpnFPM, viewmatrix[2]); + +// viewmatrix[0][3] = 0; +// viewmatrix[1][3] = 0; +// viewmatrix[2][3] = 0; + + R_ConcatTransforms8_24FPM (viewmatrix, rotationmatrix, aliastransformFPM); + +// do the scaling up of x and y to screen coordinates as part of the transform +// for the unclipped case (it would mess up clipping in the clipped case). +// Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y +// correspondingly so the projected x and y come out right +// FIXME: make this work for clipped case too? + if (trivial_accept) + { + for (i=0 ; i<4 ; i++) + { + //Debug: deleteme: + fixedpoint8_24_t tmp=FPM_FROMFLOATC8_24(((float)1.0) / ((float)0x8000 * 0x10000)); + float f=((float)1.0) / ((float)0x8000 * 0x10000); + float f2=((float)0x8000 * 0x10000); + //Dan: potential bug area (overflow / underflow) + aliastransformFPM[0][i] = fpm_DivInt64_8_24(fpm_Mul8_24(aliastransformFPM[0][i], fpm_FromFixedPoint(aliasxscaleFPM)), + (0x8000 * (__int64)0x10000)); + aliastransformFPM[1][i] = fpm_Mul8_24(aliastransformFPM[1][i], + fpm_DivInt64_8_24(fpm_FromFixedPoint(aliasyscaleFPM), + (0x8000 * (__int64)0x10000))); + aliastransformFPM[2][i] = fpm_DivInt64_8_24(aliastransformFPM[2][i], (0x8000 * (__int64)0x10000)); + +// aliastransformFPM[0][i] = fpm_Mul8_24(fpm_Mul8_24(aliastransformFPM[0][i], fpm_FromFixedPoint(aliasxscaleFPM)), +// FPM_FROMFLOATC8_24(((float)1.0) / ((float)0x8000 * 0x10000))); +// aliastransformFPM[1][i] = fpm_Mul8_24(fpm_Mul8_24(aliastransformFPM[1][i], fpm_FromFixedPoint(aliasyscaleFPM)), +// FPM_FROMFLOATC8_24(((float)1.0) / ((float)0x8000 * 0x10000))); +// aliastransformFPM[2][i] = fpm_Mul8_24(aliastransformFPM[2][i], FPM_FROMFLOATC8_24(((float)1.0) / ((float)0x8000 * 0x10000))); +// aliastransformFPM[1][i] = FPM_FROMFLOAT(FPM_TOFLOAT(aliastransformFPM[1][i]) * FPM_TOFLOAT(aliasyscaleFPM)* +// (((float)1.0) / ((float)0x8000 * 0x10000))); +// aliastransformFPM[2][i] = FPM_FROMFLOAT(FPM_TOFLOAT(aliastransformFPM[2][i])* ((float)1.0) / ((float)0x8000 * 0x10000)); + + } + } +} +#endif //USEFPM + +/* +================ +R_AliasTransformFinalVert +================ +*/ +void R_AliasTransformFinalVert (finalvert_t *fv, auxvert_t *av, + trivertx_t *pverts, stvert_t *pstverts) +{ + int temp; + float lightcos, *plightnormal; + + av->fv[0] = DotProduct(pverts->v, aliastransform[0]) + + aliastransform[0][3]; + av->fv[1] = DotProduct(pverts->v, aliastransform[1]) + + aliastransform[1][3]; + av->fv[2] = DotProduct(pverts->v, aliastransform[2]) + + aliastransform[2][3]; + + fv->v[2] = pstverts->s; + fv->v[3] = pstverts->t; + + fv->flags = pstverts->onseam; + +// lighting + plightnormal = r_avertexnormals[pverts->lightnormalindex]; + lightcos = DotProduct (plightnormal, r_plightvec); + temp = r_ambientlight; + + if (lightcos < 0) + { + temp += (int)(r_shadelight * lightcos); + + // clamp; because we limited the minimum ambient and shading light, we + // don't have to clamp low light, just bright + if (temp < 0) + temp = 0; + } + + fv->v[4] = temp; +} + + +/* +================ +R_AliasTransformFinalVert +================ +*/ +#ifdef USEFPM +void R_AliasTransformFinalVertFPM (finalvert_t *fv, auxvert_FPM_t *av, + trivertx_t *pverts, stvert_t *pstverts) +{ + int temp; + fixedpoint_t lightcos, *plightnormal; + + av->fv[0] = FPM_ADD(DotProduct8_24FPM(pverts->v, aliastransformFPM[0]), + aliastransformFPM[0][3]); + av->fv[1] = FPM_ADD(DotProduct8_24FPM(pverts->v, aliastransformFPM[1]), + aliastransformFPM[1][3]); + av->fv[2] = FPM_ADD(DotProduct8_24FPM(pverts->v, aliastransformFPM[2]), + aliastransformFPM[2][3]); + + fv->v[2] = pstverts->s; + fv->v[3] = pstverts->t; + + fv->flags = pstverts->onseam; + +// lighting + plightnormal = r_avertexnormalsFPM[pverts->lightnormalindex]; + lightcos = DotProductFPM (plightnormal, r_plightvecFPM); + temp = r_ambientlight; + + if (lightcos < 0) + { + temp += FPM_TOLONG(FPM_MUL(r_shadelightFPM, lightcos)); + + // clamp; because we limited the minimum ambient and shading light, we + // don't have to clamp low light, just bright + if (temp < 0) + temp = 0; + } + + fv->v[4] = temp; +} +#endif //USEFPM + +#if !id386 + +/* +================ +R_AliasTransformAndProjectFinalVerts +================ +*/ +void R_AliasTransformAndProjectFinalVerts (finalvert_t *fv, stvert_t *pstverts) +{ + int i, temp; + float lightcos, *plightnormal, zi; + trivertx_t *pverts; + + GpError("R_AliasTFPFinalVert A",13); + + pverts = r_apverts; + + + for (i=0 ; iv, aliastransform[2]) + + aliastransform[2][3]); + + // x, y, and z are scaled down by 1/2**31 in the transform, so 1/z is + // scaled up by 1/2**31, and the scaling cancels out for x and y in the + // projection + fv->v[5] = (int)zi; + + fv->v[0] = (int)(((DotProduct(pverts->v, aliastransform[0]) + + aliastransform[0][3]) * zi) + aliasxcenter); + fv->v[1] = (int)(((DotProduct(pverts->v, aliastransform[1]) + + aliastransform[1][3]) * zi) + aliasycenter); + + fv->v[2] = pstverts->s; + fv->v[3] = pstverts->t; + fv->flags = pstverts->onseam; + + // lighting + plightnormal = r_avertexnormals[pverts->lightnormalindex]; + lightcos = DotProduct (plightnormal, r_plightvec); + temp = r_ambientlight; + + if (lightcos < 0) + { + temp += (int)(r_shadelight * lightcos); + + // clamp; because we limited the minimum ambient and shading light, we + // don't have to clamp low light, just bright + if (temp < 0) + temp = 0; + } + + fv->v[4] = temp; + + } + GpError("R_AliasTFPFinalVert end",13); +} + +#ifdef USEFPM +void R_AliasTransformAndProjectFinalVertsFPM (finalvert_t *fv, stvert_t *pstverts) +{ + int i, temp; + fixedpoint_t lightcos, *plightnormal, zi; + trivertx_t *pverts; + vec3_FPM_t danTmp; + + + pverts = r_apverts; + + for (i=0 ; iv[0]); + danTmp[1]=FPM_FROMLONG(pverts->v[1]); + danTmp[2]=FPM_FROMLONG(pverts->v[2]); + + zi = FPM_INV(FPM_ADD(DotProduct8_24FPM(danTmp, aliastransformFPM[2]), + aliastransformFPM[2][3])); + + // x, y, and z are scaled down by 1/2**31 in the transform, so 1/z is + // scaled up by 1/2**31, and the scaling cancels out for x and y in the + // projection + fv->v[5] = FPM_TOLONG(zi); + + fv->v[0] = FPM_TOLONG(FPM_ADD(FPM_MUL(FPM_ADD(DotProduct8_24FPM(danTmp, aliastransformFPM[0]), + aliastransformFPM[0][3]), zi), aliasxcenterFPM)); + fv->v[1] = FPM_TOLONG(FPM_ADD(FPM_MUL(FPM_ADD(DotProduct8_24FPM(danTmp, aliastransformFPM[1]), + aliastransformFPM[1][3]), zi), aliasycenterFPM)); + + fv->v[2] = pstverts->s; + fv->v[3] = pstverts->t; + fv->flags = pstverts->onseam; + + // lighting + plightnormal = r_avertexnormalsFPM[pverts->lightnormalindex]; + lightcos = DotProductFPM (plightnormal, r_plightvecFPM); + temp = r_ambientlight; + + if (lightcos < 0) + { + temp += FPM_TOLONG(FPM_MUL(r_shadelightFPM, lightcos)); + + // clamp; because we limited the minimum ambient and shading light, we + // don't have to clamp low light, just bright + if (temp < 0) + temp = 0; + } + + fv->v[4] = temp; + } +} +#endif //USEFPM +#endif + + +/* +================ +R_AliasProjectFinalVert +================ +*/ +void R_AliasProjectFinalVert (finalvert_t *fv, auxvert_t *av) +{ + float zi; + +// project points + zi = ((float)1.0) / av->fv[2]; + + fv->v[5] = (int) (zi * ziscale); + + fv->v[0] = (int)((av->fv[0] * aliasxscale * zi) + aliasxcenter); + fv->v[1] = (int)((av->fv[1] * aliasyscale * zi) + aliasycenter); +} + +#ifdef USEFPM +void R_AliasProjectFinalVertFPM (finalvert_t *fv, auxvert_FPM_t *av) +{ + fixedpoint8_24_t zi; +// project points + zi = av->fv[2]; + zi = fpm_Inv8_24(zi); + + fv->v[5] = (long)(ziscaleFPM/fpm_ToLong(av->fv[2])); +// fpm_ToFixedPoint(fpm_Mul8_24(ziscaleFPM, zi)); + + fv->v[0] = FPM_TOLONG(FPM_ADD(fpm_MulMixed8_24(zi, fpm_Mul(av->fv[0],aliasxscaleFPM)), aliasxcenterFPM)); +// fv->v[0] = FPM_TOLONG(FPM_MUL(FPM_MUL(av->fv[0],aliasxscaleFPM),zi)) + aliasxcenterFPM; +// fv->v[0] = (av->fv[0] * aliasxscale * zi) + aliasxcenter; + fv->v[1] = FPM_TOLONG(FPM_ADD(fpm_MulMixed8_24(zi, fpm_Mul(av->fv[1],aliasxscaleFPM)), aliasycenterFPM)); +// fv->v[1] = FPM_TOLONG(FPM_MUL(FPM_MUL(av->fv[1],aliasxscaleFPM),zi)) + aliasycenterFPM; +// fv->v[1] = (av->fv[1] * aliasyscale * zi) + aliasycenter; +} +#endif //USEFPM + +/* +================ +R_AliasPrepareUnclippedPoints +================ +*/ +void R_AliasPrepareUnclippedPoints (void) +{ + stvert_t *pstverts; + finalvert_t *fv; + + GpError("R_AliasPrepareUnliccpedPoints A",12); + + pstverts = (stvert_t *)((byte *)paliashdr + paliashdr->stverts); + r_anumverts = pmdl->numverts; +// FIXME: just use pfinalverts directly? + fv = pfinalverts; + + GpError("R_AliasPrepareUnliccpedPoints B",12); + R_AliasTransformAndProjectFinalVerts (fv, pstverts); + + if (r_affinetridesc.drawtype){ + GpError("R_AliasPrepareUnliccpedPoints B",13); + D_PolysetDrawFinalVerts (fv, r_anumverts); + } + + r_affinetridesc.pfinalverts = pfinalverts; + r_affinetridesc.ptriangles = (mtriangle_t *) + ((byte *)paliashdr + paliashdr->triangles); + r_affinetridesc.numtriangles = pmdl->numtris; + + GpError("R_AliasPrepareUnliccpedPoints C",13); + D_PolysetDraw (); + GpError("R_AliasPrepareUnliccpedPoints end",13); +} + +#ifdef USEFPM +void R_AliasPrepareUnclippedPointsFPM (void) +{ + stvert_t *pstverts; + finalvert_t *fv; + + pstverts = (stvert_t *)((byte *)paliashdr + paliashdr->stverts); + r_anumverts = pmdlFPM->numverts; +// FIXME: just use pfinalverts directly? + fv = pfinalverts; + + R_AliasTransformAndProjectFinalVertsFPM (fv, pstverts); + + if (r_affinetridesc.drawtype) + // D_PolysetDrawFinalVertsFPM (fv, r_anumverts); // FPM doesn't exist + D_PolysetDrawFinalVerts (fv, r_anumverts); + + r_affinetridesc.pfinalverts = pfinalverts; + r_affinetridesc.ptriangles = (mtriangle_t *) + ((byte *)paliashdr + paliashdr->triangles); + r_affinetridesc.numtriangles = pmdlFPM->numtris; + + D_PolysetDraw (); +} +#endif //USEFPM +/* +=============== +R_AliasSetupSkin +=============== +*/ +void R_AliasSetupSkin (void) +{ + int skinnum; + int i, numskins; + maliasskingroup_t *paliasskingroup; + float *pskinintervals, fullskininterval; + float skintargettime, skintime; + + skinnum = currententity->skinnum; + if ((skinnum >= pmdl->numskins) || (skinnum < 0)) + { + Con_DPrintf ("R_AliasSetupSkin: no such skin # %d\n", skinnum); + skinnum = 0; + } + + pskindesc = ((maliasskindesc_t *) + ((byte *)paliashdr + paliashdr->skindesc)) + skinnum; + a_skinwidth = pmdl->skinwidth; + + if (pskindesc->type == ALIAS_SKIN_GROUP) + { + paliasskingroup = (maliasskingroup_t *)((byte *)paliashdr + + pskindesc->skin); + pskinintervals = (float *) + ((byte *)paliashdr + paliasskingroup->intervals); + numskins = paliasskingroup->numskins; + fullskininterval = pskinintervals[numskins-1]; + + skintime = ((float)cl.time) + currententity->syncbase; + + // when loading in Mod_LoadAliasSkinGroup, we guaranteed all interval + // values are positive, so we don't have to worry about division by 0 + skintargettime = skintime - + ((int)(skintime / fullskininterval)) * fullskininterval; + + for (i=0 ; i<(numskins-1) ; i++) + { + if (pskinintervals[i] > skintargettime) + break; + } + + pskindesc = &paliasskingroup->skindescs[i]; + } + + r_affinetridesc.pskindesc = pskindesc; + r_affinetridesc.pskin = (void *)((byte *)paliashdr + pskindesc->skin); + r_affinetridesc.skinwidth = a_skinwidth; + r_affinetridesc.seamfixupX16 = (a_skinwidth >> 1) << 16; + r_affinetridesc.skinheight = pmdl->skinheight; +} + +#ifdef USEFPM +void R_AliasSetupSkinFPM (void) +{ + int skinnum; + int i, numskins; + maliasskingroup_t *paliasskingroup; + fixedpoint_t *pskinintervals, fullskininterval; + float skintargettime, skintime; + + skinnum = currententityFPM->skinnum; + if ((skinnum >= pmdlFPM->numskins) || (skinnum < 0)) + { + Con_DPrintf ("R_AliasSetupSkin: no such skin # %d\n", skinnum); + skinnum = 0; + } + + pskindesc = ((maliasskindesc_t *) + ((byte *)paliashdr + paliashdr->skindesc)) + skinnum; + a_skinwidth = pmdlFPM->skinwidth; + + if (pskindesc->type == ALIAS_SKIN_GROUP) + { + paliasskingroup = (maliasskingroup_t *)((byte *)paliashdr + + pskindesc->skin); + //Dan: I'm not sure about the following... + pskinintervals = (fixedpoint_t *) + ((byte *)paliashdr + paliasskingroup->intervals); + numskins = paliasskingroup->numskins; + fullskininterval = pskinintervals[numskins-1]; + + skintime = ((float)clFPM.time) + currententityFPM->syncbase; + + // when loading in Mod_LoadAliasSkinGroup, we guaranteed all interval + // values are positive, so we don't have to worry about division by 0 + skintargettime = skintime - + ((int)(skintime / fullskininterval)) * fullskininterval; + + for (i=0 ; i<(numskins-1) ; i++) + { + if (pskinintervals[i] > skintargettime) + break; + } + + pskindesc = &paliasskingroup->skindescs[i]; + } + + r_affinetridesc.pskindesc = pskindesc; + r_affinetridesc.pskin = (void *)((byte *)paliashdr + pskindesc->skin); + r_affinetridesc.skinwidth = a_skinwidth; + r_affinetridesc.seamfixupX16 = (a_skinwidth >> 1) << 16; + r_affinetridesc.skinheight = pmdlFPM->skinheight; +} +#endif //USEFPM +/* +================ +R_AliasSetupLighting +================ +*/ +void R_AliasSetupLighting (alight_t *plighting) +{ + +// guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have +// to clamp off the bottom + r_ambientlight = plighting->ambientlight; + + if (r_ambientlight < LIGHT_MIN) + r_ambientlight = LIGHT_MIN; + + r_ambientlight = (255 - r_ambientlight) << VID_CBITS; + + if (r_ambientlight < LIGHT_MIN) + r_ambientlight = LIGHT_MIN; + + r_shadelight = (float)plighting->shadelight; + + if (r_shadelight < 0) + r_shadelight = 0; + + r_shadelight *= VID_GRADES; + +// rotate the lighting vector into the model's frame of reference + r_plightvec[0] = DotProduct (plighting->plightvec, alias_forward); + r_plightvec[1] = -DotProduct (plighting->plightvec, alias_right); + r_plightvec[2] = DotProduct (plighting->plightvec, alias_up); +} + +#ifdef USEFPM +void R_AliasSetupLightingFPM (alight_FPM_t *plighting) +{ + +// guarantee that no vertex will ever be lit below LIGHT_MIN, so we don't have +// to clamp off the bottom + r_ambientlight = plighting->ambientlight; + + if (r_ambientlight < LIGHT_MIN) + r_ambientlight = LIGHT_MIN; + + r_ambientlight = (255 - r_ambientlight) << VID_CBITS; + + if (r_ambientlight < LIGHT_MIN) + r_ambientlight = LIGHT_MIN; + + r_shadelightFPM = FPM_FROMLONG(plighting->shadelight); + + if (r_shadelightFPM < 0) + r_shadelightFPM = 0; + + r_shadelightFPM = FPM_MUL(r_shadelightFPM, FPM_FROMLONG(VID_GRADES)); + +// rotate the lighting vector into the model's frame of reference + r_plightvecFPM[0] = DotProductFPM (plighting->plightvec, alias_forwardFPM); + r_plightvecFPM[1] = -DotProductFPM (plighting->plightvec, alias_rightFPM); + r_plightvecFPM[2] = DotProductFPM (plighting->plightvec, alias_upFPM); +} +#endif //USEFPM +/* +================= +R_AliasSetupFrame + +set r_apverts +================= +*/ +void R_AliasSetupFrame (void) +{ + int frame; + int i, numframes; + maliasgroup_t *paliasgroup; + float *pintervals, fullinterval, targettime, time; + + frame = currententity->frame; + if ((frame >= pmdl->numframes) || (frame < 0)) + { + Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame); + frame = 0; + } + + if (paliashdr->frames[frame].type == ALIAS_SINGLE) + { + r_apverts = (trivertx_t *) + ((byte *)paliashdr + paliashdr->frames[frame].frame); + return; + } + + paliasgroup = (maliasgroup_t *) + ((byte *)paliashdr + paliashdr->frames[frame].frame); + pintervals = (float *)((byte *)paliashdr + paliasgroup->intervals); + numframes = paliasgroup->numframes; + fullinterval = pintervals[numframes-1]; + + time = ((float)cl.time) + currententity->syncbase; + +// +// when loading in Mod_LoadAliasGroup, we guaranteed all interval values +// are positive, so we don't have to worry about division by 0 +// + targettime = time - ((int)(time / fullinterval)) * fullinterval; + + for (i=0 ; i<(numframes-1) ; i++) + { + if (pintervals[i] > targettime) + break; + } + + r_apverts = (trivertx_t *) + ((byte *)paliashdr + paliasgroup->frames[i].frame); +} + +#ifdef USEFPM +void R_AliasSetupFrameFPM (void) +{ + int frame; + int i, numframes; + maliasgroup_t *paliasgroup; + float *pintervals, fullinterval, targettime, time; + + frame = currententityFPM->frame; + if ((frame >= pmdlFPM->numframes) || (frame < 0)) + { + Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame); + frame = 0; + } + + if (paliashdr->frames[frame].type == ALIAS_SINGLE) + { + r_apverts = (trivertx_t *) + ((byte *)paliashdr + paliashdr->frames[frame].frame); + return; + } + + paliasgroup = (maliasgroup_t *) + ((byte *)paliashdr + paliashdr->frames[frame].frame); + pintervals = (float *)((byte *)paliashdr + paliasgroup->intervals); + numframes = paliasgroup->numframes; + fullinterval = pintervals[numframes-1]; + + time = ((float)clFPM.time) + currententityFPM->syncbase; + +// +// when loading in Mod_LoadAliasGroup, we guaranteed all interval values +// are positive, so we don't have to worry about division by 0 +// + targettime = time - ((int)(time / fullinterval)) * fullinterval; + + for (i=0 ; i<(numframes-1) ; i++) + { + if (pintervals[i] > targettime) + break; + } + + r_apverts = (trivertx_t *) + ((byte *)paliashdr + paliasgroup->frames[i].frame); +} +#endif //USEFPM + +//extern finalvert_t *finalverts; +//extern auxvert_t *auxverts; + + +#ifdef USEFPM + auxvert_FPM_t auxverts[MAXALIASVERTS]; +#else +// auxvert_t auxverts[MAXALIASVERTS]; +#endif + + +/* +================ +R_AliasDrawModel +================ +*/ +void R_AliasDrawModel (alight_t *plighting) +{ +finalvert_t finalverts[MAXALIASVERTS + ((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 1]; + auxvert_t auxverts[MAXALIASVERTS]; +// finalvert_t *finalverts; +// auxvert_t *auxverts; + + + //Anders> Change malloc to static allocated memory to avoid malloc? + // finalverts = malloc( (sizeof(finalvert_t)*MAXALIASVERTS) + (sizeof(finalvert_t)*(((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 1))); + // auxverts = malloc( (sizeof(finalvert_t)*MAXALIASVERTS)); + + GpError("R_AliasDrawModel A",11); + + r_amodels_drawn++; + +// cache align + pfinalverts = (finalvert_t *) + (((long)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + pauxverts = &auxverts[0]; + + GpError("R_AliasDrawModel B",11); + + paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model); + pmdl = (mdl_t *)((byte *)paliashdr + paliashdr->model); + + GpError("R_AliasDrawModel C",11); + R_AliasSetupSkin (); + GpError("R_AliasDrawModel D",11); + R_AliasSetUpTransform (currententity->trivial_accept); + GpError("R_AliasDrawModel E",11); + R_AliasSetupLighting (plighting); + GpError("R_AliasDrawModel F",11); + R_AliasSetupFrame (); + GpError("R_AliasDrawModel G",11); + + if (!currententity->colormap) + Sys_Error ("R_AliasDrawModel: !currententity->colormap"); + + r_affinetridesc.drawtype = (currententity->trivial_accept == 3) && + r_recursiveaffinetriangles; + + if (r_affinetridesc.drawtype) + { + GpError("R_AliasDrawModel H",11); + D_PolysetUpdateTables (); // FIXME: precalc... + } + else + { +#if id386 + D_Aff8Patch (currententity->colormap); +#endif + } + + acolormap = currententity->colormap; + + if (currententity != &cl.viewent) + ziscale = (float)0x8000 * (float)0x10000; + else + ziscale = (float)0x8000 * (float)0x10000 * 3.0; + + if (currententity->trivial_accept){ + GpError("R_AliasDrawModel I",11); + R_AliasPrepareUnclippedPoints (); + } + else{ + GpError("R_AliasDrawModel J",11); + R_AliasPreparePoints (); + } + // free(finalverts); + // free(auxverts); + GpError("R_AliasDrawModel end",11); +} + +#ifdef USEFPM +void R_AliasDrawModelFPM (alight_FPM_t *plighting) +{ + +// finalvert_t finalverts[MAXALIASVERTS + +// ((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 1]; +// auxvert_FPM_t auxverts[MAXALIASVERTS]; +// finalvert_t *finalverts; +// auxvert_t *auxverts; + + //Anders> Change malloc to static allocated memory to avoid malloc? + // finalverts = malloc( (sizeof(finalvert_t)*MAXALIASVERTS) + (sizeof(finalvert_t)*(((CACHE_SIZE - 1) / sizeof(finalvert_t)) + 1))); + // auxverts = malloc( (sizeof(finalvert_t)*MAXALIASVERTS)); + + return; + + r_amodels_drawn++; + +// cache align + pfinalverts = (finalvert_t *) + (((long)&finalverts[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + pauxvertsFPM = &auxverts[0]; + + paliashdr = (aliashdr_t *)Mod_ExtradataFPM (currententityFPM->model); + pmdlFPM = (mdl_FPM_t *)((byte *)paliashdr + paliashdr->model); + + R_AliasSetupSkinFPM (); + R_AliasSetUpTransformFPM (currententityFPM->trivial_accept); + R_AliasSetupLightingFPM (plighting); + R_AliasSetupFrameFPM (); + + if (!currententityFPM->colormap) + Sys_Error ("R_AliasDrawModel: !currententity->colormap"); + + r_affinetridesc.drawtype = (currententityFPM->trivial_accept == 3) && + r_recursiveaffinetriangles; + + if (r_affinetridesc.drawtype) + { + D_PolysetUpdateTables (); // FIXME: precalc... + } + else + { +#if id386 + D_Aff8Patch (currententityFPM->colormap); +#endif + } + + acolormap = currententityFPM->colormap; + + if (currententityFPM != &clFPM.viewent) + ziscaleFPM = ((unsigned long)0x8000 * (unsigned long)0x10000); + else { + ziscaleFPM = ((unsigned long)0x8000 * (unsigned long)0x10000); + ziscaleFPM *= 3; + } + + if (currententityFPM->trivial_accept) + R_AliasPrepareUnclippedPointsFPM (); + else + R_AliasPreparePointsFPM (); + + free(finalverts); + free(auxverts); +} +#endif //USEFPM diff --git a/project/jni/application/quake/source/r_bsp.c b/project/jni/application/quake/source/r_bsp.c new file mode 100644 index 000000000..d96ab5810 --- /dev/null +++ b/project/jni/application/quake/source/r_bsp.c @@ -0,0 +1,837 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_bsp.c + +#include "quakedef.h" +#include "r_local.h" +#ifdef DEBUG +#include "../LogFloat.h" +#endif + +// +// current entity info +// +qboolean insubmodel; +entity_t *currententity; + +vec3_t modelorg, base_modelorg; + +#ifdef USE_PQ_OPT1 +int modelorg_fxp[3]; +#endif + + // modelorg is the viewpoint reletive to + // the currently rendering entity +vec3_t r_entorigin; // the currently rendering entity in world + // coordinates + +float entity_rotation[3][3]; + + +vec3_t r_worldmodelorg; + +int r_currentbkey; + +typedef enum {touchessolid, drawnode, nodrawnode} solidstate_t; + +#define MAX_BMODEL_VERTS 500 // 6K +#define MAX_BMODEL_EDGES 1000 // 12K + +static mvertex_t *pbverts; +static bedge_t *pbedges; +static int numbverts, numbedges; + +static mvertex_t *pfrontenter, *pfrontexit; + + +static qboolean makeclippededge; + +#ifdef USEFPM +entity_FPM_t *currententityFPM; +vec3_FPM_t modelorgFPM, base_modelorgFPM; +vec3_FPM_t r_entoriginFPM; +fixedpoint_t entity_rotationFPM[3][3]; +vec3_FPM_t r_worldmodelorgFPM; +static mvertex_FPM_t *pbvertsFPM; +static bedge_FPM_t *pbedgesFPM; +static mvertex_FPM_t *pfrontenterFPM, *pfrontexitFPM; +#endif //USEFPM +//=========================================================================== + +/* +================ +R_EntityRotate +================ +*/ +void R_EntityRotate (vec3_t vec) +{ + vec3_t tvec; + + VectorCopy (vec, tvec); + vec[0] = DotProduct (entity_rotation[0], tvec); + vec[1] = DotProduct (entity_rotation[1], tvec); + vec[2] = DotProduct (entity_rotation[2], tvec); +} + + +/* +================ +R_RotateBmodel +================ +*/ +void R_RotateBmodel (void) +{ + float angle, s, c, temp1[3][3], temp2[3][3], temp3[3][3]; + +// TODO: should use a look-up table +// TODO: should really be stored with the entity instead of being reconstructed +// TODO: could cache lazily, stored in the entity +// TODO: share work with R_SetUpAliasTransform + +// yaw + angle = currententity->angles[YAW]; + angle = angle * (float) M_PI*2 / 360; + s = (float)sin(angle); + c = (float)cos(angle); + + temp1[0][0] = c; + temp1[0][1] = s; + temp1[0][2] = 0; + temp1[1][0] = -s; + temp1[1][1] = c; + temp1[1][2] = 0; + temp1[2][0] = 0; + temp1[2][1] = 0; + temp1[2][2] = 1; + + +// pitch + angle = currententity->angles[PITCH]; + angle = angle * (float)M_PI*2 / 360; + s = (float)sin(angle); + c = (float)cos(angle); + + temp2[0][0] = c; + temp2[0][1] = 0; + temp2[0][2] = -s; + temp2[1][0] = 0; + temp2[1][1] = 1; + temp2[1][2] = 0; + temp2[2][0] = s; + temp2[2][1] = 0; + temp2[2][2] = c; + + R_ConcatRotations (temp2, temp1, temp3); + +// roll + angle = currententity->angles[ROLL]; + angle = angle * (float)M_PI*2 / 360; + s = (float)sin(angle); + c = (float)cos(angle); + + temp1[0][0] = 1; + temp1[0][1] = 0; + temp1[0][2] = 0; + temp1[1][0] = 0; + temp1[1][1] = c; + temp1[1][2] = s; + temp1[2][0] = 0; + temp1[2][1] = -s; + temp1[2][2] = c; + + R_ConcatRotations (temp1, temp3, entity_rotation); + +// +// rotate modelorg and the transformation matrix +// + R_EntityRotate (modelorg); + R_EntityRotate (vpn); + R_EntityRotate (vright); + R_EntityRotate (vup); + + R_TransformFrustum (); +} + + +/* +================ +R_RecursiveClipBPoly +================ +*/ +void R_RecursiveClipBPoly (bedge_t *pedges, mnode_t *pnode, msurface_t *psurf) +{ + bedge_t *psideedges[2], *pnextedge, *ptedge; + int i, side, lastside; + float dist, frac, lastdist; + mplane_t *splitplane, tplane; + mvertex_t *pvert, *plastvert, *ptvert; + mnode_t *pn; + + psideedges[0] = psideedges[1] = NULL; + + makeclippededge = false; + +// transform the BSP plane into model space +// FIXME: cache these? + splitplane = pnode->plane; + tplane.dist = splitplane->dist - + DotProduct(r_entorigin, splitplane->normal); + tplane.normal[0] = DotProduct (entity_rotation[0], splitplane->normal); + tplane.normal[1] = DotProduct (entity_rotation[1], splitplane->normal); + tplane.normal[2] = DotProduct (entity_rotation[2], splitplane->normal); + +// clip edges to BSP plane + for ( ; pedges ; pedges = pnextedge) + { + pnextedge = pedges->pnext; + + // set the status for the last point as the previous point + // FIXME: cache this stuff somehow? + plastvert = pedges->v[0]; + lastdist = DotProduct (plastvert->position, tplane.normal) - + tplane.dist; + + if (lastdist > 0) + lastside = 0; + else + lastside = 1; + + pvert = pedges->v[1]; + + dist = DotProduct (pvert->position, tplane.normal) - tplane.dist; + + if (dist > 0) + side = 0; + else + side = 1; + + if (side != lastside) + { + // clipped + if (numbverts >= MAX_BMODEL_VERTS) + return; + + // generate the clipped vertex + frac = lastdist / (lastdist - dist); + ptvert = &pbverts[numbverts++]; + ptvert->position[0] = plastvert->position[0] + + frac * (pvert->position[0] - + plastvert->position[0]); + ptvert->position[1] = plastvert->position[1] + + frac * (pvert->position[1] - + plastvert->position[1]); + ptvert->position[2] = plastvert->position[2] + + frac * (pvert->position[2] - + plastvert->position[2]); + + // split into two edges, one on each side, and remember entering + // and exiting points + // FIXME: share the clip edge by having a winding direction flag? + if (numbedges >= (MAX_BMODEL_EDGES - 1)) + { + Con_Printf ("Out of edges for bmodel\n"); + return; + } + + ptedge = &pbedges[numbedges]; + ptedge->pnext = psideedges[lastside]; + psideedges[lastside] = ptedge; + ptedge->v[0] = plastvert; + ptedge->v[1] = ptvert; + + ptedge = &pbedges[numbedges + 1]; + ptedge->pnext = psideedges[side]; + psideedges[side] = ptedge; + ptedge->v[0] = ptvert; + ptedge->v[1] = pvert; + + numbedges += 2; + + if (side == 0) + { + // entering for front, exiting for back + pfrontenter = ptvert; + makeclippededge = true; + } + else + { + pfrontexit = ptvert; + makeclippededge = true; + } + } + else + { + // add the edge to the appropriate side + pedges->pnext = psideedges[side]; + psideedges[side] = pedges; + } + } + +// if anything was clipped, reconstitute and add the edges along the clip +// plane to both sides (but in opposite directions) + if (makeclippededge) + { + if (numbedges >= (MAX_BMODEL_EDGES - 2)) + { + Con_Printf ("Out of edges for bmodel\n"); + return; + } + + ptedge = &pbedges[numbedges]; + ptedge->pnext = psideedges[0]; + psideedges[0] = ptedge; + ptedge->v[0] = pfrontexit; + ptedge->v[1] = pfrontenter; + + ptedge = &pbedges[numbedges + 1]; + ptedge->pnext = psideedges[1]; + psideedges[1] = ptedge; + ptedge->v[0] = pfrontenter; + ptedge->v[1] = pfrontexit; + + numbedges += 2; + } + +// draw or recurse further + for (i=0 ; i<2 ; i++) + { + if (psideedges[i]) + { + // draw if we've reached a non-solid leaf, done if all that's left is a + // solid leaf, and continue down the tree if it's not a leaf + pn = pnode->children[i]; + + // we're done with this branch if the node or leaf isn't in the PVS + if (pn->visframe == r_visframecount) + { + if (pn->contents < 0) + { + if (pn->contents != CONTENTS_SOLID) + { + r_currentbkey = ((mleaf_t *)pn)->key; + R_RenderBmodelFace (psideedges[i], psurf); + } + } + else + { + R_RecursiveClipBPoly (psideedges[i], pnode->children[i], + psurf); + } + } + } + } +} + + +/* +================ +R_DrawSolidClippedSubmodelPolygons +================ +*/ +void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel) +{ + int i, j, lindex; + vec_t dot; + msurface_t *psurf; + int numsurfaces; + mplane_t *pplane; + mvertex_t bverts[MAX_BMODEL_VERTS]; + bedge_t bedges[MAX_BMODEL_EDGES], *pbedge; + medge_t *pedge, *pedges; + +// FIXME: use bounding-box-based frustum clipping info? + + psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; + numsurfaces = pmodel->nummodelsurfaces; + pedges = pmodel->edges; + + for (i=0 ; iplane; + + dot = DotProduct (modelorg, pplane->normal) - pplane->dist; + + // draw the polygon + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + // FIXME: use bounding-box-based frustum clipping info? + + // copy the edges to bedges, flipping if necessary so always + // clockwise winding + // FIXME: if edges and vertices get caches, these assignments must move + // outside the loop, and overflow checking must be done here + pbverts = bverts; + pbedges = bedges; + numbverts = numbedges = 0; + + if (psurf->numedges > 0) + { + pbedge = &bedges[numbedges]; + numbedges += psurf->numedges; + + for (j=0 ; jnumedges ; j++) + { + lindex = pmodel->surfedges[psurf->firstedge+j]; + + if (lindex > 0) + { + pedge = &pedges[lindex]; + pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[0]]; + pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[1]]; + } + else + { + lindex = -lindex; + pedge = &pedges[lindex]; + pbedge[j].v[0] = &r_pcurrentvertbase[pedge->v[1]]; + pbedge[j].v[1] = &r_pcurrentvertbase[pedge->v[0]]; + } + + pbedge[j].pnext = &pbedge[j+1]; + } + + pbedge[j-1].pnext = NULL; // mark end of edges + + R_RecursiveClipBPoly (pbedge, currententity->topnode, psurf); + } + else + { + Sys_Error ("no edges in bmodel"); + } + } + } +} + + +/* +================ +R_DrawSubmodelPolygons +================ +*/ +void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags) +{ + int i; + vec_t dot; + msurface_t *psurf; + int numsurfaces; + mplane_t *pplane; + +// FIXME: use bounding-box-based frustum clipping info? + psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; + numsurfaces = pmodel->nummodelsurfaces; + + for (i=0 ; iplane; + + dot = DotProduct (modelorg, pplane->normal) - pplane->dist; + + // draw the polygon + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + r_currentkey = ((mleaf_t *)currententity->topnode)->key; + + // FIXME: use bounding-box-based frustum clipping info? + R_RenderFace (psurf, clipflags); + } + } +} + +#ifdef USEFPM +void R_DrawSubmodelPolygonsFPM (model_FPM_t *pmodel, int clipflags) +{ + int i; + fixedpoint_t dot; + msurface_FPM_t *psurf; + int numsurfaces; + mplane_FPM_t *pplane; + +// FIXME: use bounding-box-based frustum clipping info? + + psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; + numsurfaces = pmodel->nummodelsurfaces; + + for (i=0 ; iplane; + + dot = FPM_SUB(DotProductFPM (modelorgFPM, pplane->normal), pplane->dist); + + // draw the polygon + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + r_currentkey = ((mleaf_FPM_t *)currententityFPM->topnode)->key; + + // FIXME: use bounding-box-based frustum clipping info? + // R_RenderFaceFPM (psurf, clipflags); // FPM doesn't exist + R_RenderFace (psurf, clipflags); + } + } +} +#endif //USEFPM + +void VerifyFrustumIndexes(char *s) { + int i, ii; + char buf[256]; + + for (i=0; i<4; i++) + if (pfrustum_indexes[i]) + for (ii=0; ii<4; ii++) + if (pfrustum_indexes[i][ii]<0) { + sprintf(buf, "Bad Frustum: [%d][%d]=%d\n%s", i,ii,pfrustum_indexes[i][ii],s); + Sys_Error(buf); + } +} + +#ifdef USE_PQ_OPT1 +int clipplanes_fxp[4][3]; +int clipdist_fxp[4]; +#endif + +/* +================ +R_RecursiveWorldNode +================ +*/ +void R_RecursiveWorldNode (mnode_t *node, int clipflags) +{ + int i, c, side, *pindex; + mplane_t *plane; + msurface_t *surf, **mark; + mleaf_t *pleaf; + double dot; +#ifdef USE_PQ_OPT1 + int d_fxp; +#else + double d; + vec3_t acceptpt, rejectpt; +#endif + + if (node->contents == CONTENTS_SOLID) + return; // solid + + if (node->visframe != r_visframecount) + return; + +// cull the clipping planes if not trivial accept +// FIXME: the compiler is doing a lousy job of optimizing here; it could be +// twice as fast in ASM + if (clipflags) + { + for (i=0 ; i<4 ; i++) + { + if (! (clipflags & (1<minmaxs[pindex[0]]*clipplanes_fxp[i][0]+node->minmaxs[pindex[1]]*clipplanes_fxp[i][1]+node->minmaxs[pindex[2]]*clipplanes_fxp[i][2]; + d_fxp-=clipdist_fxp[i]; + + if (d_fxp <= 0) + return; + + d_fxp=node->minmaxs[pindex[3]]*clipplanes_fxp[i][0]+node->minmaxs[pindex[4]]*clipplanes_fxp[i][1]+node->minmaxs[pindex[5]]*clipplanes_fxp[i][2]; + d_fxp-=clipdist_fxp[i]; + + if (d_fxp >= 0) + clipflags &= ~(1<minmaxs[pindex[0]]; + rejectpt[1] = (float)node->minmaxs[pindex[1]]; + rejectpt[2] = (float)node->minmaxs[pindex[2]]; + + d = DotProduct (rejectpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d <= 0) + return; + + acceptpt[0] = (float)node->minmaxs[pindex[3+0]]; + acceptpt[1] = (float)node->minmaxs[pindex[3+1]]; + acceptpt[2] = (float)node->minmaxs[pindex[3+2]]; + + d = DotProduct (acceptpt, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d >= 0) + clipflags &= ~(1<contents < 0) + { + pleaf = (mleaf_t *)node; + + mark = pleaf->firstmarksurface; + c = pleaf->nummarksurfaces; + + if (c) + { + do + { + (*mark)->visframe = r_framecount; + mark++; + } while (--c); + } + + // deal with model fragments in this leaf + if (pleaf->efrags) + { + R_StoreEfrags (&pleaf->efrags); + } + + pleaf->key = r_currentkey; + r_currentkey++; // all bmodels in a leaf share the same key + } + else + { + // node is just a decision point, so go down the apropriate sides + + // find which side of the node we are on + plane = node->plane; + + switch (plane->type) + { + case PLANE_X: + dot = modelorg[0] - plane->dist; + break; + case PLANE_Y: + dot = modelorg[1] - plane->dist; + break; + case PLANE_Z: + dot = modelorg[2] - plane->dist; + break; + default: + dot = DotProduct (modelorg, plane->normal) - plane->dist; + break; + } + + if (dot >= 0) + side = 0; + else + side = 1; + + // recurse down the children, front side first + R_RecursiveWorldNode (node->children[side], clipflags); + + // draw stuff + c = node->numsurfaces; + + if (c) + { + surf = cl.worldmodel->surfaces + node->firstsurface; + + if (dot < -BACKFACE_EPSILON) + { + do + { + if ((surf->flags & SURF_PLANEBACK) && + (surf->visframe == r_framecount)) + + { + if (r_drawpolys) + { + if (r_worldpolysbacktofront) + { + if (numbtofpolys < MAX_BTOFPOLYS) + { + pbtofpolys[numbtofpolys].clipflags = + clipflags; + pbtofpolys[numbtofpolys].psurf = surf; + numbtofpolys++; + } + } + else + { + R_RenderPoly (surf, clipflags); + } + } + else + { + + R_RenderFace (surf, clipflags); + + } + } + + surf++; + } while (--c); + } + else if (dot > BACKFACE_EPSILON) + { + do + { + if (!(surf->flags & SURF_PLANEBACK) && + (surf->visframe == r_framecount)) + + { + if (r_drawpolys) + { + if (r_worldpolysbacktofront) + { + if (numbtofpolys < MAX_BTOFPOLYS) + { + pbtofpolys[numbtofpolys].clipflags = + clipflags; + pbtofpolys[numbtofpolys].psurf = surf; + numbtofpolys++; + } + } + else + { + R_RenderPoly (surf, clipflags); + } + } + else + { + + R_RenderFace (surf, clipflags); + + } + } + + surf++; + } while (--c); + } + + // all surfaces on the same node share the same sequence number + r_currentkey++; + } + + // recurse down the back side + R_RecursiveWorldNode (node->children[!side], clipflags); + + } +} + +/* +================ +R_RenderWorld +================ +*/ +void R_RenderWorld (void) +{ + int i; + model_t *clmodel; + btofpoly_t btofpolys[MAX_BTOFPOLYS]; + + GpError("A",8); + + pbtofpolys = btofpolys; + + currententity = &cl_entities[0]; + VectorCopy (r_origin, modelorg); + +#ifdef USE_PQ_OPT1 + modelorg_fxp[0]=(int)(r_origin[0]*524288.0); + modelorg_fxp[1]=(int)(r_origin[1]*524288.0); + modelorg_fxp[2]=(int)(r_origin[2]*524288.0); + + //modelorg_fxp[0]=(int)(r_origin[0]*65536.0); + //modelorg_fxp[1]=(int)(r_origin[1]*65536.0); + //modelorg_fxp[2]=(int)(r_origin[2]*65536.0); + + vright_fxp[0]=(int)(256.0/vright[0]); + if (!vright_fxp[0]) vright_fxp[0]=0x7fffffff; + vright_fxp[1]=(int)(256.0/vright[1]); + if (!vright_fxp[1]) vright_fxp[1]=0x7fffffff; + vright_fxp[2]=(int)(256.0/vright[2]); + if (!vright_fxp[2]) vright_fxp[2]=0x7fffffff; + + vpn_fxp[0]=(int)(256.0/vpn[0]); + if (!vpn_fxp[0]) vpn_fxp[0]=0x7fffffff; + vpn_fxp[1]=(int)(256.0/vpn[1]); + if (!vpn_fxp[1]) vpn_fxp[1]=0x7fffffff; + vpn_fxp[2]=(int)(256.0/vpn[2]); + if (!vpn_fxp[2]) vpn_fxp[2]=0x7fffffff; + + vup_fxp[0]=(int)(256.0/vup[0]); + if (!vup_fxp[0]) vup_fxp[0]=0x7fffffff; + vup_fxp[1]=(int)(256.0/vup[1]); + if (!vup_fxp[1]) vup_fxp[1]=0x7fffffff; + vup_fxp[2]=(int)(256.0/vup[2]); + if (!vup_fxp[2]) vup_fxp[2]=0x7fffffff; + +#endif + + clmodel = currententity->model; + r_pcurrentvertbase = clmodel->vertexes; + +#ifdef USE_PQ_OPT2 + r_pcurrentvertbase_fxp = clmodel->vertexes_fxp; +#endif +#ifdef USE_PQ_OPT1 + //Dan Fixed point conversion stuff + for (i=0; i<4; i++) { + clipplanes_fxp[i][0]=(int)(view_clipplanes[i].normal[0]*65536.0); + clipplanes_fxp[i][1]=(int)(view_clipplanes[i].normal[1]*65536.0); + clipplanes_fxp[i][2]=(int)(view_clipplanes[i].normal[2]*65536.0); + clipdist_fxp[i] =(int)(view_clipplanes[i].dist*65536.0); +#ifdef USE_PQ_OPT2 + view_clipplanes_fxp[i].leftedge=view_clipplanes[i].leftedge; + view_clipplanes_fxp[i].rightedge=view_clipplanes[i].rightedge; + if (!view_clipplanes[i].normal[0]) view_clipplanes_fxp[i].normal[0]=2<<29; + else view_clipplanes_fxp[i].normal[0]=(int)(4096.0f/view_clipplanes[i].normal[0]); + if (!view_clipplanes[i].normal[0]) view_clipplanes_fxp[i].normal[0]=2<<29; + + if (!view_clipplanes[i].normal[1]) view_clipplanes_fxp[i].normal[1]=2<<29; + else view_clipplanes_fxp[i].normal[1]=(int)(4096.0f/view_clipplanes[i].normal[1]); + if (!view_clipplanes[i].normal[1]) view_clipplanes_fxp[i].normal[1]=2<<29; + + if (!view_clipplanes[i].normal[2]) view_clipplanes_fxp[i].normal[2]=2<<29; + else view_clipplanes_fxp[i].normal[2]=(int)(4096.0f/view_clipplanes[i].normal[2]); + if (!view_clipplanes[i].normal[2]) view_clipplanes_fxp[i].normal[2]=2<<29; + + view_clipplanes_fxp[i].dist=(int)(view_clipplanes[i].dist*128.0f); +#endif +#if defined(_X86_)&&defined(DEBUG) + LogFloat(view_clipplanes[i].normal[0], "view_clipplanes[i].normal[0]", i, -1); + LogFloat(view_clipplanes[i].normal[1], "view_clipplanes[i].normal[1]", i, -1); + LogFloat(view_clipplanes[i].normal[2], "view_clipplanes[i].normal[2]", i, -1); +#endif + } +#endif + + R_RecursiveWorldNode (clmodel->nodes, 15); + +// if the driver wants the polygons back to front, play the visible ones back +// in that order + if (r_worldpolysbacktofront) + { + for (i=numbtofpolys-1 ; i>=0 ; i--) + { + R_RenderPoly (btofpolys[i].psurf, btofpolys[i].clipflags); + } + } + +} + diff --git a/project/jni/application/quake/source/r_draw.c b/project/jni/application/quake/source/r_draw.c new file mode 100644 index 000000000..5a2a3f9fa --- /dev/null +++ b/project/jni/application/quake/source/r_draw.c @@ -0,0 +1,1936 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// r_draw.c + +#include "quakedef.h" +#include "r_local.h" +#include "d_local.h" // FIXME: shouldn't need to include this + +#include "LogFloat.h" + +#define MAXLEFTCLIPEDGES 100 + +// !!! if these are changed, they must be changed in asm_draw.h too !!! +#define FULLY_CLIPPED_CACHED 0x80000000 +#define FRAMECOUNT_MASK 0x7FFFFFFF + +unsigned int cacheoffset; + +int c_faceclip; // number of faces clipped + +zpointdesc_t r_zpointdesc; + +polydesc_t r_polydesc; + + +clipplane_t *entity_clipplanes; +clipplane_t view_clipplanes[4]; +clipplane_t world_clipplanes[16]; + +#ifdef USE_PQ_OPT2 +clipplane_fxp_t view_clipplanes_fxp[4]; +#endif + +medge_t *r_pedge; + +qboolean r_leftclipped, r_rightclipped; +static qboolean makeleftedge, makerightedge; +qboolean r_nearzionly; + +int sintable[SIN_BUFFER_SIZE]; +int intsintable[SIN_BUFFER_SIZE]; + +mvertex_t r_leftenter, r_leftexit; +mvertex_t r_rightenter, r_rightexit; + +#ifdef USE_PQ_OPT2 +mvertex_fxp_t r_leftenter_fxp, r_leftexit_fxp; +mvertex_fxp_t r_rightenter_fxp, r_rightexit_fxp; +#endif + +typedef struct +{ + float u,v; + int ceilv; +} evert_t; + +int r_emitted; +float r_nearzi; +float r_u1, r_v1, r_lzi1; +fixedpoint_t r_nearziFPM; +int r_ceilv1; + +#ifdef USE_PQ_OPT1 +int r_u1_fxp, r_v1_fxp, r_lzi1_fxp; +extern int modelorg_fxp[3]; +#endif + +qboolean r_lastvertvalid; + +#ifdef USEFPM +zpointdesc_FPM_t r_zpointdescFPM; +polydesc_FPM_t r_polydescFPM; +clipplane_FPM_t view_clipplanesFPM[4]; +mvertex_FPM_t r_leftenterFPM, r_leftexitFPM; +mvertex_FPM_t r_rightenterFPM, r_rightexitFPM; +fixedpoint_t r_u1FPM, r_v1FPM, r_lzi1FPM; +#endif //USEFPM + +#if !id386 + +/* +================ +R_EmitEdge +================ +*/ +void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1) +{ + edge_t *edge, *pcheck; + int u_check; + float u, u_step; + vec3_t local, transformed; + float *world; + int v, v2, ceilv0; + float scale, lzi0, u0, v0; + int side; + + if (r_lastvertvalid) + { + u0 = r_u1; + v0 = r_v1; + lzi0 = r_lzi1; + ceilv0 = r_ceilv1; + } + else + { + world = &pv0->position[0]; + + /* + world[0]=LogFloat(world[0], "R_EmitEdge::world", 0, -1); + world[1]=LogFloat(world[1], "R_EmitEdge::world", 1, -1); + world[2]=LogFloat(world[2], "R_EmitEdge::world", 2, -1); + */ + // transform and project + VectorSubtract (world, modelorg, local); + /* + modelorg[0]=LogFloat(modelorg[0], "R_EmitEdge::modelorg", 0, -1); + modelorg[1]=LogFloat(modelorg[1], "R_EmitEdge::modelorg", 1, -1); + modelorg[2]=LogFloat(modelorg[2], "R_EmitEdge::modelorg", 2, -1); + + local[0]=LogFloat(local[0], "R_EmitEdge::local", 0, -1); + local[1]=LogFloat(local[1], "R_EmitEdge::local", 1, -1); + local[2]=LogFloat(local[2], "R_EmitEdge::local", 2, -1); + */ + TransformVector (local, transformed); + /* + LogFloat(vright[0], "vright", 0, -1); + LogFloat(vright[1], "vright", 1, -1); + LogFloat(vright[2], "vright", 2, -1); + LogFloat(vup[0], "vup", 0, -1); + LogFloat(vup[1], "vup", 1, -1); + LogFloat(vup[2], "vup", 2, -1); + LogFloat(vpn[0], "vpn", 0, -1); + LogFloat(vpn[1], "vpn", 1, -1); + LogFloat(vpn[2], "vpn", 2, -1); + + transformed[0]=LogFloat(transformed[0], "R_EmitEdge::transformed", 0, -1); + transformed[1]=LogFloat(transformed[1], "R_EmitEdge::transformed", 1, -1); + */ + if (transformed[2] < NEAR_CLIP) + transformed[2] = (float)NEAR_CLIP; + + //transformed[2]=LogFloat(transformed[2], "R_EmitEdge::transformed", 2, -1); + + + //LogFloat(yscale, "yscale", -1, -1); + //LogFloat(transformed[1], "transformed", 1, -1); + //LogFloat(transformed[2], "transformed", 2, -1); + //LogFloat(yscale/transformed[2], "value1", -1, -1); + //LogFloat((yscale/transformed[2])*transformed[1], "value2", -1, -1); + + + lzi0 = (float)(1.0 / transformed[2]); + + // FIXME: build x/yscale into transform? + scale = xscale * lzi0; + //scale=LogFloat(scale, "R_EmitEdge::scale{x}", -1, -1); + u0 = (xcenter + scale*transformed[0]); + + if (u0 < r_refdef.fvrectx_adj) + u0 = r_refdef.fvrectx_adj; + if (u0 > r_refdef.fvrectright_adj) + u0 = r_refdef.fvrectright_adj; + + scale = yscale * lzi0; + //scale=LogFloat(scale, "R_EmitEdge::scale{y}", -1, -1); + v0 = (ycenter - scale*transformed[1]); + + if (v0 < r_refdef.fvrecty_adj) + v0 = r_refdef.fvrecty_adj; + if (v0 > r_refdef.fvrectbottom_adj) + v0 = r_refdef.fvrectbottom_adj; + + ceilv0 = (int) ceil(v0); + } + /* + u0=LogFloat(u0, "R_EmitEdge::u0", -1, -1); + v0=LogFloat(v0, "R_EmitEdge::v0", -1, -1); + pv1->position[0]=LogFloat(pv1->position[0], "R_EmitEdge::pv1->position", 0, -1); + */ + world = &pv1->position[0]; + +// transform and project + VectorSubtract (world, modelorg, local); + TransformVector (local, transformed); + + if (transformed[2] < NEAR_CLIP) + transformed[2] = (float)NEAR_CLIP; + + r_lzi1 = (float)(1.0 / transformed[2]); + + //xscale=LogFloat(xscale, "R_EmitEdge::xscale", -1, -1); + scale = xscale * r_lzi1; + r_u1 = (xcenter + scale*transformed[0]); + if (r_u1 < r_refdef.fvrectx_adj) + r_u1 = r_refdef.fvrectx_adj; + if (r_u1 > r_refdef.fvrectright_adj) + r_u1 = r_refdef.fvrectright_adj; + + //r_u1=LogFloat(r_u1, "r_u1", -1, -1); + //yscale=LogFloat(yscale, "R_EmitEdge::yscale", -1, -1); + scale = yscale * r_lzi1; + r_v1 = (ycenter - scale*transformed[1]); + if (r_v1 < r_refdef.fvrecty_adj) + r_v1 = r_refdef.fvrecty_adj; + if (r_v1 > r_refdef.fvrectbottom_adj) + r_v1 = r_refdef.fvrectbottom_adj; + + //r_v1=LogFloat(r_v1, "r_v1", -1, -1); + + if (r_lzi1 > lzi0) + lzi0 = r_lzi1; + + if (lzi0 > r_nearzi) // for mipmap finding + r_nearzi = lzi0; + +// for right edges, all we want is the effect on 1/z + if (r_nearzionly) + return; + + r_emitted = 1; + + r_ceilv1 = (int) ceil(r_v1); + + +// create the edge + if (ceilv0 == r_ceilv1) + { + // we cache unclipped horizontal edges as fully clipped + if (cacheoffset != 0x7FFFFFFF) + { + cacheoffset = FULLY_CLIPPED_CACHED | + (r_framecount & FRAMECOUNT_MASK); + } + + return; // horizontal edge + } + + side = ceilv0 > r_ceilv1; + + edge = edge_p++; + + edge->owner = NULL; + + edge->owner = r_pedge; + + edge->nearzi = lzi0; + + if (side == 0) + { + // trailing edge (go from p1 to p2) + v = ceilv0; + v2 = r_ceilv1 - 1; + + edge->surfs[0] = surface_p - surfaces; + edge->surfs[1] = 0; + + u_step = ((r_u1 - u0) / (r_v1 - v0)); + u = u0 + ((float)v - v0) * u_step; + } + else + { + // leading edge (go from p2 to p1) + v2 = ceilv0 - 1; + v = r_ceilv1; + + edge->surfs[0] = 0; + edge->surfs[1] = surface_p - surfaces; + + u_step = ((u0 - r_u1) / (v0 - r_v1)); + u = r_u1 + ((float)v - r_v1) * u_step; + } + //u=LogFloat(u, "R_EmitEdge::u", -1, -1); + //u_step=LogFloat(u_step, "R_EmitEdge::u_step", -1, -1); + + + edge->u_step = (int)(u_step*0x100000); + edge->u = (int)(u*0x100000 + 0xFFFFF); + + +// we need to do this to avoid stepping off the edges if a very nearly +// horizontal edge is less than epsilon above a scan, and numeric error causes +// it to incorrectly extend to the scan, and the extension of the line goes off +// the edge of the screen +// FIXME: is this actually needed? + if (edge->u < r_refdef.vrect_x_adj_shift20) + edge->u = r_refdef.vrect_x_adj_shift20; + if (edge->u > r_refdef.vrectright_adj_shift20) + edge->u = r_refdef.vrectright_adj_shift20; + +// +// sort the edge in normally +// + u_check = edge->u; + if (edge->surfs[0]) + u_check++; // sort trailers after leaders + + if (!newedges[v] || newedges[v]->u >= u_check) + { + edge->next = newedges[v]; + newedges[v] = edge; + } + else + { + pcheck = newedges[v]; + while (pcheck->next && pcheck->next->u < u_check) + pcheck = pcheck->next; + edge->next = pcheck->next; + pcheck->next = edge; + } + + edge->nextremove = removeedges[v2]; + removeedges[v2] = edge; +} + +#ifdef USE_PQ_OPT2 +void R_EmitEdgeFXP_fxp (mvertex_fxp_t *pv0, mvertex_fxp_t *pv1) +{ + //This is just like R_EmitEdge_fxp, except that the vertex parameters are + //already fixed point, and don't need to be converted. + + edge_t *edge, *pcheck; + int u_check; + //float u, u_step; + int u_fxp, u_step_fxp; + //vec3_t local, transformed; + int local_fxp[3], transformed_fxp[3]; + int *world; + int v, v2, ceilv0; + //float scale, lzi0, u0, v0; + int scale_fxp, scale2_fxp, lzi0_fxp, u0_fxp, v0_fxp; + int side; + + if (r_lastvertvalid) + { + u0_fxp = r_u1_fxp; + v0_fxp = r_v1_fxp; + lzi0_fxp = r_lzi1_fxp; + //lzi0 = r_lzi1; + ceilv0 = r_ceilv1; + } + else + { + //world_fxp=(int)(pv0->position[0]*(float)(2^16)); + world = &pv0->position[0]; + + // transform and project + //VectorSubtract (world, modelorg, local); + //Vector Subtract (and convert) + local_fxp[0]=world[0]-modelorg_fxp[0]; + local_fxp[1]=world[1]-modelorg_fxp[1]; + local_fxp[2]=world[2]-modelorg_fxp[2]; + + //TransformVector (local, transformed); + //transformed_fxp[0] = (int)(local_fxp[0]*vright[0])+(int)(local_fxp[1]*vright[1])+(int)(local_fxp[2]*vright[2]); + //transformed_fxp[1] = (int)(local_fxp[0]*vup[0])+(int)(local_fxp[1]*vup[1])+(int)(local_fxp[2]*vup[2]); + //transformed_fxp[2] = (int)(local_fxp[0]*vpn[0])+(int)(local_fxp[1]*vpn[1])+(int)(local_fxp[2]*vpn[2]); + + //13.19 / 24.8 = 21.11 + transformed_fxp[0] = local_fxp[0]/vright_fxp[0]+local_fxp[1]/vright_fxp[1]+local_fxp[2]/vright_fxp[2]; + transformed_fxp[1] = local_fxp[0]/vup_fxp[0]+local_fxp[1]/vup_fxp[1]+local_fxp[2]/vup_fxp[2]; + transformed_fxp[2] = local_fxp[0]/vpn_fxp[0]+local_fxp[1]/vpn_fxp[1]+local_fxp[2]/vpn_fxp[2]; + + if (transformed_fxp[2] < (int)(NEAR_CLIP*2048.0)) + transformed_fxp[2] = (int)(NEAR_CLIP*2048.0); + + transformed_fxp[0]/=16; //21.11->25.7 + transformed_fxp[1]/=16; //21.11->25.7 + transformed_fxp[2]/=8; //21.11->24.8 + + lzi0_fxp=transformed_fxp[2]; + //lzi0 = (float)(1.0 / transformed[2]); + + // FIXME: build x/yscale into transform? + //scale = xscale * lzi0; + //u0 = (xcenter + scale*transformed[0]); + + //Dan: Is this needed? + if (!transformed_fxp[2]) scale_fxp=0; + else scale_fxp=xscale_fxp/transformed_fxp[2]; //9.23 / 24.8 = 17.15 + scale2_fxp=transformed_fxp[0]*(scale_fxp); // 25.7 * 17.15 = 10.22 + + if (transformed_fxp[0]<0) { + if (scale2_fxp>0) scale2_fxp=-511*4194304; + } else { + if (scale2_fxp<0) scale2_fxp=511*4194304; + } + + u0_fxp=scale2_fxp+xcenter_fxp; + + if (u0_fxp < r_refdef_fvrectx_adj_fxp) + u0_fxp = r_refdef_fvrectx_adj_fxp; + if (u0_fxp > r_refdef_fvrectright_adj_fxp) + u0_fxp = r_refdef_fvrectright_adj_fxp; + + //scale = yscale * lzi0; + //v0 = (ycenter - scale*transformed[1]); + + //Dan: Is this needed? + if (!transformed_fxp[2]) scale_fxp=0; + else scale_fxp=yscale_fxp/transformed_fxp[2]; //9.23 / 24.8 = 17.15 + scale2_fxp=transformed_fxp[1]*(scale_fxp); // 25.7 * 17.15 = 10.22 + + if (transformed_fxp[1]<0) { + if (scale2_fxp>0) scale2_fxp=-511*4194304; + } else { + if (scale2_fxp<0) scale2_fxp=511*4194304; //255*8388608; + } + + v0_fxp = ycenter_fxp-scale2_fxp; + + if (v0_fxp < r_refdef_fvrecty_adj_fxp) + v0_fxp = r_refdef_fvrecty_adj_fxp; + if (v0_fxp > r_refdef_fvrectbottom_adj_fxp) + v0_fxp = r_refdef_fvrectbottom_adj_fxp; + + ceilv0 = v0_fxp/4194304; + if (v0_fxp&0x3FFFFF) ceilv0++; + } + + //world(pv1->position[0]*(float)(2^16)); + world = &pv1->position[0]; + +// transform and project + //VectorSubtract (world, modelorg, local); + //Vector Subtract (and convert) + local_fxp[0]=world[0]-modelorg_fxp[0]; + local_fxp[1]=world[1]-modelorg_fxp[1]; + local_fxp[2]=world[2]-modelorg_fxp[2]; + + //TransformVector (local, transformed); + //transformed_fxp[0] = ((int)(local_fxp[0]*vright[0]))+((int)(local_fxp[1]*vright[1]))+((int)(local_fxp[2]*vright[2])); + //transformed_fxp[1] = ((int)(local_fxp[0]*vup[0]))+((int)(local_fxp[1]*vup[1]))+((int)(local_fxp[2]*vup[2])); + //transformed_fxp[2] = ((int)(local_fxp[0]*vpn[0]))+((int)(local_fxp[1]*vpn[1]))+((int)(local_fxp[2]*vpn[2])); + + transformed_fxp[0] = local_fxp[0]/vright_fxp[0]+local_fxp[1]/vright_fxp[1]+local_fxp[2]/vright_fxp[2]; + transformed_fxp[1] = local_fxp[0]/vup_fxp[0]+local_fxp[1]/vup_fxp[1]+local_fxp[2]/vup_fxp[2]; + transformed_fxp[2] = local_fxp[0]/vpn_fxp[0]+local_fxp[1]/vpn_fxp[1]+local_fxp[2]/vpn_fxp[2]; + + if (transformed_fxp[2] < (int)(NEAR_CLIP*2048.0)) + transformed_fxp[2] = (int)(NEAR_CLIP*2048.0); + + transformed_fxp[0]/=16; + transformed_fxp[1]/=16; + transformed_fxp[2]/=8; + + r_lzi1_fxp=transformed_fxp[2]; + //r_lzi1 = (float)(1.0 / transformed[2]); + //scale = xscale * r_lzi1; + + //Dan: Is this needed? + if (!transformed_fxp[2]) scale_fxp=0; + else scale_fxp=xscale_fxp/transformed_fxp[2]; //9.23 / 24.8 = 17.15 + scale2_fxp=transformed_fxp[0]*(scale_fxp); // 24.8 * 17.15 = 9.23 //21.11 + + if (transformed_fxp[0]<0) { + if (scale2_fxp>0) scale2_fxp=-511*4194304; + } else { + if (scale2_fxp<0) scale2_fxp=511*4194304; + } + + //r_u1 = (xcenter + scale*transformed[0]); + r_u1_fxp = xcenter_fxp + scale2_fxp; + if (r_u1_fxp < r_refdef_fvrectx_adj_fxp) + r_u1_fxp = r_refdef_fvrectx_adj_fxp; + if (r_u1_fxp > r_refdef_fvrectright_adj_fxp) + r_u1_fxp = r_refdef_fvrectright_adj_fxp; + + //scale = yscale * r_lzi1; + //r_v1 = (ycenter - scale*transformed[1]); + + //Dan: Is this needed? + if (!transformed_fxp[2]) scale_fxp=0; + else scale_fxp=yscale_fxp/transformed_fxp[2]; //9.23 / 24.8 = 17.15 + scale2_fxp=transformed_fxp[1]*(scale_fxp); // 23.9 * 17.15 = 9.23 //21.11 + + if (transformed_fxp[1]<0) { + if (scale2_fxp>0) scale2_fxp=-511*4194304; + } else { + if (scale2_fxp<0) scale2_fxp=511*4194304; + } + + r_v1_fxp = ycenter_fxp - scale2_fxp; + if (r_v1_fxp < r_refdef_fvrecty_adj_fxp) + r_v1_fxp = r_refdef_fvrecty_adj_fxp; + if (r_v1_fxp > r_refdef_fvrectbottom_adj_fxp) + r_v1_fxp = r_refdef_fvrectbottom_adj_fxp; + + //if (r_lzi1 > lzi0) + // lzi0 = r_lzi1; + if (r_lzi1_fxp < lzi0_fxp) + lzi0_fxp = r_lzi1_fxp; + + //if (lzi0 > r_nearzi) // for mipmap finding + // r_nearzi = lzi0; + if (/*128*/128.0/lzi0_fxp > r_nearzi) { // for mipmap finding + //if (!lzi0_fxp) r_nearzi=0; + //else + r_nearzi = (float)(128.0/lzi0_fxp); + } + +// for right edges, all we want is the effect on 1/z + if (r_nearzionly) + return; + + r_emitted = 1; + + //r_ceilv1 = (int) ceil(r_v1); + r_ceilv1 = r_v1_fxp/4194304; + if (r_v1_fxp&0x3FFFFF) r_ceilv1++; + + +// create the edge + if (ceilv0 == r_ceilv1) + { + // we cache unclipped horizontal edges as fully clipped + if (cacheoffset != 0x7FFFFFFF) + { + cacheoffset = FULLY_CLIPPED_CACHED | + (r_framecount & FRAMECOUNT_MASK); + } + + return; // horizontal edge + } + + side = ceilv0 > r_ceilv1; + + edge = edge_p++; + + edge->owner = NULL; + + edge->owner = r_pedge; + + //Dan: Is this needed? + if (!lzi0_fxp) edge->nearzi=0.0; + else edge->nearzi = (float)(128.0f/*256.0*//lzi0_fxp); + + if (side == 0) + { + int tmp; + // trailing edge (go from p1 to p2) + v = ceilv0; + v2 = r_ceilv1 - 1; + + edge->surfs[0] = surface_p - surfaces; + edge->surfs[1] = 0; + + //u_step = ((r_u1 - u0) / (r_v1 - v0)); + //u = u0 + ((float)v - v0) * u_step; + + tmp=((r_v1_fxp - v0_fxp)>>10); + if (tmp) + u_step_fxp=(r_u1_fxp - u0_fxp) / tmp; //10.22 / 15.12 = 22.10 + else + u_step_fxp=0; + u_fxp = u0_fxp + ((v*4194304 - v0_fxp)>>12 * u_step_fxp>>12); + } + else + { + int tmp; + // leading edge (go from p2 to p1) + v2 = ceilv0 - 1; + v = r_ceilv1; + + edge->surfs[0] = 0; + edge->surfs[1] = surface_p - surfaces; + + //u_step = ((u0 - r_u1) / (v0 - r_v1)); + //u = r_u1 + ((float)v - r_v1) * u_step; + + tmp=((v0_fxp - r_v1_fxp)>>10); + if (tmp) + u_step_fxp = (u0_fxp - r_u1_fxp) / tmp; + else + u_step_fxp=0; + u_fxp = r_u1_fxp + ((v*4194304 - r_v1_fxp)>>12 * u_step_fxp>>12); + + } + //edge->u_step = tmp*0x100000; + //edge->u = (int)(/*(u_fxp/65536)*0x100000*/u_fxp/4 + 0xFFFFF); + + edge->u_step = u_step_fxp*1024;///16; //tmp*0x100000; + edge->u = (int)(/*(u_fxp/65536)*0x100000*/u_fxp/4 + 0xFFFFF); + +// we need to do this to avoid stepping off the edges if a very nearly +// horizontal edge is less than epsilon above a scan, and numeric error causes +// it to incorrectly extend to the scan, and the extension of the line goes off +// the edge of the screen +// FIXME: is this actually needed? + if (edge->u < r_refdef.vrect_x_adj_shift20) + edge->u = r_refdef.vrect_x_adj_shift20; + if (edge->u > r_refdef.vrectright_adj_shift20) + edge->u = r_refdef.vrectright_adj_shift20; + +// +// sort the edge in normally +// + u_check = edge->u; + if (edge->surfs[0]) + u_check++; // sort trailers after leaders + + if (!newedges[v] || newedges[v]->u >= u_check) + { + edge->next = newedges[v]; + newedges[v] = edge; + } + else + { + pcheck = newedges[v]; + while (pcheck->next && pcheck->next->u < u_check) + pcheck = pcheck->next; + edge->next = pcheck->next; + pcheck->next = edge; + } + + edge->nextremove = removeedges[v2]; + removeedges[v2] = edge; +} +#endif + +#ifdef USE_PQ_OPT1 +void R_EmitEdge_fxp (mvertex_t *pv0, mvertex_t *pv1) +{ + edge_t *edge, *pcheck; + int u_check; + //float u, u_step; + int u_fxp, u_step_fxp; + //vec3_t local, transformed; + int local_fxp[3], transformed_fxp[3]; + float *world; + int v, v2, ceilv0; + //float scale, lzi0, u0, v0; + int scale_fxp, scale2_fxp, lzi0_fxp, u0_fxp, v0_fxp; + int side; + + if (r_lastvertvalid) + { + u0_fxp = r_u1_fxp; + v0_fxp = r_v1_fxp; + lzi0_fxp = r_lzi1_fxp; + //lzi0 = r_lzi1; + ceilv0 = r_ceilv1; + } + else + { + //world_fxp=(int)(pv0->position[0]*(float)(2^16)); + world = &pv0->position[0]; + + // transform and project + //VectorSubtract (world, modelorg, local); + //Vector Subtract (and convert) + local_fxp[0]=((int)(world[0]*(524288.0)))-modelorg_fxp[0]; + local_fxp[1]=((int)(world[1]*(524288.0)))-modelorg_fxp[1]; + local_fxp[2]=((int)(world[2]*(524288.0)))-modelorg_fxp[2]; + + //TransformVector (local, transformed); + //transformed_fxp[0] = (int)(local_fxp[0]*vright[0])+(int)(local_fxp[1]*vright[1])+(int)(local_fxp[2]*vright[2]); + //transformed_fxp[1] = (int)(local_fxp[0]*vup[0])+(int)(local_fxp[1]*vup[1])+(int)(local_fxp[2]*vup[2]); + //transformed_fxp[2] = (int)(local_fxp[0]*vpn[0])+(int)(local_fxp[1]*vpn[1])+(int)(local_fxp[2]*vpn[2]); + + transformed_fxp[0] = local_fxp[0]/vright_fxp[0]+local_fxp[1]/vright_fxp[1]+local_fxp[2]/vright_fxp[2]; + //transformed_fxp[0]*=256; + transformed_fxp[1] = local_fxp[0]/vup_fxp[0]+local_fxp[1]/vup_fxp[1]+local_fxp[2]/vup_fxp[2]; + //transformed_fxp[1]*=256; + transformed_fxp[2] = local_fxp[0]/vpn_fxp[0]+local_fxp[1]/vpn_fxp[1]+local_fxp[2]/vpn_fxp[2]; + transformed_fxp[2]*=256; + + if (transformed_fxp[2] < (int)(NEAR_CLIP*1048576.0)) + transformed_fxp[2] = (int)(NEAR_CLIP*1048576.0); + + transformed_fxp[0]/=16; + transformed_fxp[1]/=16; + transformed_fxp[2]/=2048; + + lzi0_fxp=transformed_fxp[2]; + //lzi0 = (float)(1.0 / transformed[2]); + + // FIXME: build x/yscale into transform? + //scale = xscale * lzi0; + //u0 = (xcenter + scale*transformed[0]); + + scale_fxp=xscale_fxp/transformed_fxp[2]; //9.23 / 24.8 = 17.15 + scale2_fxp=transformed_fxp[0]*(scale_fxp); // 25.7 * 17.15 = 10.22 + + if (transformed_fxp[0]<0) { + if (scale2_fxp>0) scale2_fxp=-511*4194304; + } else { + if (scale2_fxp<0) scale2_fxp=511*4194304; + } + + u0_fxp=scale2_fxp+xcenter_fxp; + + if (u0_fxp < r_refdef_fvrectx_adj_fxp) + u0_fxp = r_refdef_fvrectx_adj_fxp; + if (u0_fxp > r_refdef_fvrectright_adj_fxp) + u0_fxp = r_refdef_fvrectright_adj_fxp; + + //scale = yscale * lzi0; + //v0 = (ycenter - scale*transformed[1]); + scale_fxp=yscale_fxp/transformed_fxp[2]; //9.23 / 24.8 = 17.15 + scale2_fxp=transformed_fxp[1]*(scale_fxp); // 25.7 * 17.15 = 10.22 + + if (transformed_fxp[1]<0) { + if (scale2_fxp>0) scale2_fxp=-511*4194304; + } else { + if (scale2_fxp<0) scale2_fxp=511*4194304; //255*8388608; + } + + v0_fxp = ycenter_fxp-scale2_fxp; + + if (v0_fxp < r_refdef_fvrecty_adj_fxp) + v0_fxp = r_refdef_fvrecty_adj_fxp; + if (v0_fxp > r_refdef_fvrectbottom_adj_fxp) + v0_fxp = r_refdef_fvrectbottom_adj_fxp; + + ceilv0 = v0_fxp/4194304; + if (v0_fxp&0x3FFFFF) ceilv0++; + } + + //world(pv1->position[0]*(float)(2^16)); + world = &pv1->position[0]; + +// transform and project + //VectorSubtract (world, modelorg, local); + //Vector Subtract (and convert) + local_fxp[0]=((int)(world[0]*(524288.0)))-modelorg_fxp[0]; + local_fxp[1]=((int)(world[1]*(524288.0)))-modelorg_fxp[1]; + local_fxp[2]=((int)(world[2]*(524288.0)))-modelorg_fxp[2]; + + //TransformVector (local, transformed); + //transformed_fxp[0] = ((int)(local_fxp[0]*vright[0]))+((int)(local_fxp[1]*vright[1]))+((int)(local_fxp[2]*vright[2])); + //transformed_fxp[1] = ((int)(local_fxp[0]*vup[0]))+((int)(local_fxp[1]*vup[1]))+((int)(local_fxp[2]*vup[2])); + //transformed_fxp[2] = ((int)(local_fxp[0]*vpn[0]))+((int)(local_fxp[1]*vpn[1]))+((int)(local_fxp[2]*vpn[2])); + + transformed_fxp[0] = local_fxp[0]/vright_fxp[0]+local_fxp[1]/vright_fxp[1]+local_fxp[2]/vright_fxp[2]; + //transformed_fxp[0]*=256; + transformed_fxp[1] = local_fxp[0]/vup_fxp[0]+local_fxp[1]/vup_fxp[1]+local_fxp[2]/vup_fxp[2]; + //transformed_fxp[1]*=256; + transformed_fxp[2] = local_fxp[0]/vpn_fxp[0]+local_fxp[1]/vpn_fxp[1]+local_fxp[2]/vpn_fxp[2]; + transformed_fxp[2]*=256; + + //transformed_fxp[2]=-transformed_fxp[2]; + //if (transformed[2] < NEAR_CLIP) + // transformed[2] = (float)NEAR_CLIP; + if (transformed_fxp[2] < (int)(NEAR_CLIP*524288.0)) + transformed_fxp[2] = (int)(NEAR_CLIP*524288.0); + + transformed_fxp[0]/=16; + transformed_fxp[1]/=16; + transformed_fxp[2]/=2048; + + r_lzi1_fxp=transformed_fxp[2]; + //r_lzi1 = (float)(1.0 / transformed[2]); + //scale = xscale * r_lzi1; + + scale_fxp=xscale_fxp/transformed_fxp[2]; //9.23 / 24.8 = 17.15 + scale2_fxp=transformed_fxp[0]*(scale_fxp); // 24.8 * 17.15 = 9.23 //21.11 + + if (transformed_fxp[0]<0) { + if (scale2_fxp>0) scale2_fxp=-511*4194304; + } else { + if (scale2_fxp<0) scale2_fxp=511*4194304; + } + + //r_u1 = (xcenter + scale*transformed[0]); + r_u1_fxp = xcenter_fxp + scale2_fxp; + if (r_u1_fxp < r_refdef_fvrectx_adj_fxp) + r_u1_fxp = r_refdef_fvrectx_adj_fxp; + if (r_u1_fxp > r_refdef_fvrectright_adj_fxp) + r_u1_fxp = r_refdef_fvrectright_adj_fxp; + + //scale = yscale * r_lzi1; + //r_v1 = (ycenter - scale*transformed[1]); + + scale_fxp=yscale_fxp/transformed_fxp[2]; //9.23 / 24.8 = 17.15 + scale2_fxp=transformed_fxp[1]*(scale_fxp); // 23.9 * 17.15 = 9.23 //21.11 + + if (transformed_fxp[1]<0) { + if (scale2_fxp>0) scale2_fxp=-511*4194304; + } else { + if (scale2_fxp<0) scale2_fxp=511*4194304; + } + + r_v1_fxp = ycenter_fxp - scale2_fxp; + if (r_v1_fxp < r_refdef_fvrecty_adj_fxp) + r_v1_fxp = r_refdef_fvrecty_adj_fxp; + if (r_v1_fxp > r_refdef_fvrectbottom_adj_fxp) + r_v1_fxp = r_refdef_fvrectbottom_adj_fxp; + + //if (r_lzi1 > lzi0) + // lzi0 = r_lzi1; + if (r_lzi1_fxp < lzi0_fxp) + lzi0_fxp = r_lzi1_fxp; + + //if (lzi0 > r_nearzi) // for mipmap finding + // r_nearzi = lzi0; + if (128.0/lzi0_fxp > r_nearzi) { // for mipmap finding + //if (!lzi0_fxp) r_nearzi=0; + //else + r_nearzi = (float)(128.0/lzi0_fxp); + } + +// for right edges, all we want is the effect on 1/z + if (r_nearzionly) + return; + + r_emitted = 1; + + //r_ceilv1 = (int) ceil(r_v1); + r_ceilv1 = r_v1_fxp/4194304; + if (r_v1_fxp&0x3FFFFF) r_ceilv1++; + + +// create the edge + if (ceilv0 == r_ceilv1) + { + // we cache unclipped horizontal edges as fully clipped + if (cacheoffset != 0x7FFFFFFF) + { + cacheoffset = FULLY_CLIPPED_CACHED | + (r_framecount & FRAMECOUNT_MASK); + } + + return; // horizontal edge + } + + side = ceilv0 > r_ceilv1; + + edge = edge_p++; + + edge->owner = NULL; + + edge->owner = r_pedge; + + edge->nearzi = (float)(128.0/lzi0_fxp); + + { + //float tmp; + if (side == 0) + { + //int tmp; + // trailing edge (go from p1 to p2) + v = ceilv0; + v2 = r_ceilv1 - 1; + + edge->surfs[0] = surface_p - surfaces; + edge->surfs[1] = 0; + + //u_step = ((r_u1 - u0) / (r_v1 - v0)); + //u = u0 + ((float)v - v0) * u_step; + + u_step_fxp=(r_u1_fxp - u0_fxp) / ((r_v1_fxp - v0_fxp)>>10); //10.22 / 15.12 = 22.10 + u_fxp = u0_fxp + ((v*4194304 - v0_fxp)>>12 * u_step_fxp>>12); + + //tmp=(((r_u1_fxp - u0_fxp)/8388608.0) / ((r_v1_fxp - v0_fxp)/8388608.0)); + //u_step_fxp=(int)(tmp*8388608.0); + //u_fxp = u0_fxp + (((float)v - v0_fxp/8388608.0) * tmp)*8388608.0; + } + else + { + //int tmp; + // leading edge (go from p2 to p1) + v2 = ceilv0 - 1; + v = r_ceilv1; + + edge->surfs[0] = 0; + edge->surfs[1] = surface_p - surfaces; + + //u_step = ((u0 - r_u1) / (v0 - r_v1)); + //u = r_u1 + ((float)v - r_v1) * u_step; + + u_step_fxp = (u0_fxp - r_u1_fxp) / ((v0_fxp - r_v1_fxp)>>10); + u_fxp = r_u1_fxp + ((v*4194304 - r_v1_fxp)>>12 * u_step_fxp>>12); + + //tmp=(((u0_fxp - r_u1_fxp)/8388608.0) / ((v0_fxp - r_v1_fxp)/8388608.0)); + //u_step_fxp = (int)(tmp*8388608.0); + //u_fxp = r_u1_fxp + (((float)v - r_v1_fxp/8388608.0) * tmp)*8388608.0; + } + //edge->u_step = tmp*0x100000; + //edge->u = (int)(/*(u_fxp/65536)*0x100000*/u_fxp/4 + 0xFFFFF); + + edge->u_step = u_step_fxp*1024;///16; //tmp*0x100000; + edge->u = (int)(/*(u_fxp/65536)*0x100000*/u_fxp/4 + 0xFFFFF); +} + +// we need to do this to avoid stepping off the edges if a very nearly +// horizontal edge is less than epsilon above a scan, and numeric error causes +// it to incorrectly extend to the scan, and the extension of the line goes off +// the edge of the screen +// FIXME: is this actually needed? + if (edge->u < r_refdef.vrect_x_adj_shift20) + edge->u = r_refdef.vrect_x_adj_shift20; + if (edge->u > r_refdef.vrectright_adj_shift20) + edge->u = r_refdef.vrectright_adj_shift20; + +// +// sort the edge in normally +// + u_check = edge->u; + if (edge->surfs[0]) + u_check++; // sort trailers after leaders + + if (!newedges[v] || newedges[v]->u >= u_check) + { + edge->next = newedges[v]; + newedges[v] = edge; + } + else + { + pcheck = newedges[v]; + while (pcheck->next && pcheck->next->u < u_check) + pcheck = pcheck->next; + edge->next = pcheck->next; + pcheck->next = edge; + } + + edge->nextremove = removeedges[v2]; + removeedges[v2] = edge; +} +#endif + +/* +================ +R_ClipEdge +================ +*/ +// Yoda +#pragma DISABLE_OPTIMIZATION +#ifdef USE_PQ_OPT2 +void R_ClipEdge_fxp (mvertex_fxp_t pv0[3], mvertex_fxp_t pv1[3], clipplane_fxp_t *clip) +{ + int d0_fxp, d1_fxp, f_fxp; + mvertex_fxp_t clipvert_fxp; + //12.20 + + if (clip) + { + do + { + //13.19 / 20.12 = 25.7 + d0_fxp=(pv0->position[0])/clip->normal[0]+(pv0->position[1])/clip->normal[1]+(pv0->position[2])/clip->normal[2]; + d1_fxp=(pv1->position[0])/clip->normal[0]+(pv1->position[1])/clip->normal[1]+(pv1->position[2])/clip->normal[2]; + d0_fxp-=(clip->dist); + d1_fxp-=(clip->dist); + //d0 = DotProduct (pv0->position, clip->normal) - clip->dist; + //d1 = DotProduct (pv1->position, clip->normal) - clip->dist; + + if (d0_fxp >= 0) + { + // point 0 is unclipped + if (d1_fxp >= 0) + { + // both points are unclipped + continue; + } + + // only point 1 is clipped + + // we don't cache clipped edges + cacheoffset = 0x7FFFFFFF; + + if (!(d0_fxp)) + f_fxp=2<<29; + else { + f_fxp = (((d0_fxp - d1_fxp)<<7)/(d0_fxp)); //(25.7->18.14) / 25.7 = 25.7 + if (!f_fxp) f_fxp=2<<29; + } + + + clipvert_fxp.position[0] = pv0->position[0] + + (((pv1->position[0] - pv0->position[0])/f_fxp)<<7); //13.19 / 25.7 = 20.12 + + clipvert_fxp.position[1] = pv0->position[1] + + (((pv1->position[1] - pv0->position[1])/f_fxp)<<7); + + clipvert_fxp.position[2] = pv0->position[2] + + (((pv1->position[2] - pv0->position[2])/f_fxp)<<7); + + if (clip->leftedge) + { + r_leftclipped = true; + r_leftexit_fxp = clipvert_fxp; + } + else if (clip->rightedge) + { + r_rightclipped = true; + r_rightexit_fxp = clipvert_fxp; + } + + R_ClipEdge_fxp (pv0, &clipvert_fxp, clip->next); + return; + } + else + { + // point 0 is clipped + if (d1_fxp < 0) + { + // both points are clipped + // we do cache fully clipped edges + if (!r_leftclipped) + cacheoffset = FULLY_CLIPPED_CACHED | + (r_framecount & FRAMECOUNT_MASK); + return; + } + + // only point 0 is clipped + r_lastvertvalid = false; + + // we don't cache partially clipped edges + cacheoffset = 0x7FFFFFFF; + + if (!d0_fxp) + f_fxp=2<<29; + else { + f_fxp = (((d0_fxp - d1_fxp)<<7)/d0_fxp); //12.20 / 20.12 = 24.8 + if (!f_fxp) f_fxp=2<<29; + } + + clipvert_fxp.position[0] = pv0->position[0] + + (((pv1->position[0] - pv0->position[0])/f_fxp)<<7); //12.20 / 24.8 = 20.12 + + clipvert_fxp.position[1] = pv0->position[1] + + (((pv1->position[1] - pv0->position[1])/f_fxp)<<7); + + clipvert_fxp.position[2] = pv0->position[2] + + (((pv1->position[2] - pv0->position[2])/f_fxp)<<7); + + if (clip->leftedge) + { + r_leftclipped = true; + r_leftenter_fxp = clipvert_fxp; + } + else if (clip->rightedge) + { + r_rightclipped = true; + r_rightenter_fxp = clipvert_fxp; + } + + R_ClipEdge_fxp (&clipvert_fxp, pv1, clip->next); + return; + } + } while ((clip = clip->next) != NULL); + } +/* +{ + mvertex_t p0, p1; + p0.position[0]=pv0->position[0]/524288.0f; + p0.position[1]=pv0->position[1]/524288.0f; + p0.position[2]=pv0->position[2]/524288.0f; + p1.position[0]=pv1->position[0]/524288.0f; + p1.position[1]=pv1->position[1]/524288.0f; + p1.position[2]=pv1->position[2]/524288.0f; + R_EmitEdge (&p0, &p1); +} +*/ +// add the edge + R_EmitEdgeFXP_fxp (pv0, pv1); +} +#endif + +void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip) +{ + float d0, d1, f; + mvertex_t clipvert; + + if (clip) + { + do + { + + //-- + int d0_fxp;//=(int)(d0*8192.0f); + int d1_fxp;//=(int)(d1*8192.0f); + int f_fxp, tmp; + int cn0, cn1, cn2; + + if (clip->normal[0]) + cn0=((int)(4096.0f/clip->normal[0])); + else + cn0=2<<29; + if (clip->normal[1]) + cn1=((int)(4096.0f/clip->normal[1])); + else + cn1=2<<29; + if (clip->normal[2]) + cn2=((int)(4096.0f/clip->normal[2])); + else + cn2=2<<29; + + //13.19 / 20.12 = 25.7 + d0_fxp=((int)(pv0->position[0]*524288.0f))/cn0+((int)(pv0->position[1]*524288.0f))/cn1+((int)(pv0->position[2]*524288.0f))/cn2; + d1_fxp=((int)(pv1->position[0]*524288.0f))/cn0+((int)(pv1->position[1]*524288.0f))/cn1+((int)(pv1->position[2]*524288.0f))/cn2; + d0_fxp-=((int)(clip->dist*128.0f)); + d1_fxp-=((int)(clip->dist*128.0f)); + + //-- + d0=d0_fxp/128.0f; + d1=d1_fxp/128.0f; + + //d0 = DotProduct (pv0->position, clip->normal) - clip->dist; + //d1 = DotProduct (pv1->position, clip->normal) - clip->dist; + + if (d0 >= 0) + { + // point 0 is unclipped + if (d1 >= 0) + { + // both points are unclipped + continue; + } + + // only point 1 is clipped + + // we don't cache clipped edges + cacheoffset = 0x7FFFFFFF; + + f = d0 / (d0 - d1); + clipvert.position[0] = pv0->position[0] + + f * (pv1->position[0] - pv0->position[0]); + clipvert.position[1] = pv0->position[1] + + f * (pv1->position[1] - pv0->position[1]); + clipvert.position[2] = pv0->position[2] + + f * (pv1->position[2] - pv0->position[2]); + +//-- + { + if (!(d0_fxp)) + f_fxp=2<<29; + else { + f_fxp = (((d0_fxp - d1_fxp)<<7)/(d0_fxp)); //(25.7->18.14) / 25.7 = 25.7 + if (!f_fxp) f_fxp=2<<29; + } + + //f_fxp=(int)(4096.0/f); + + tmp = ((int)(pv0->position[0]*524288.0f)) + + (((((int)(pv1->position[0]*524288.0f)) - ((int)(pv0->position[0]*524288.0f)))/f_fxp)<<7); //13.19 / 25.7 = 20.12 + //if (!tmp) tmp=1; + clipvert.position[0]=tmp/524288.0f; + + tmp = ((int)(pv0->position[1]*524288.0f)) + + (((((int)(pv1->position[1]*524288.0f)) - ((int)(pv0->position[1]*524288.0f)))/f_fxp)<<7); //12.20 / 24.8 = 20.12 + //if (!tmp) tmp=1; + clipvert.position[1]=tmp/524288.0f; + + tmp = ((int)(pv0->position[2]*524288.0f)) + + (((((int)(pv1->position[2]*524288.0f)) - ((int)(pv0->position[2]*524288.0f)))/f_fxp)<<7); //12.20 / 24.8 = 20.12 + //if (!tmp) tmp=1; + clipvert.position[2]=tmp/524288.0f; + } + pv0->position[0]=((int)(pv0->position[0]*524288.0f))/524288.0f; + pv0->position[1]=((int)(pv0->position[1]*524288.0f))/524288.0f; + pv0->position[2]=((int)(pv0->position[2]*524288.0f))/524288.0f; +////-- + if (clip->leftedge) + { + r_leftclipped = true; + r_leftexit = clipvert; + } + else if (clip->rightedge) + { + r_rightclipped = true; + r_rightexit = clipvert; + } + + R_ClipEdge (pv0, &clipvert, clip->next); + return; + } + else + { + // point 0 is clipped + if (d1 < 0) + { + // both points are clipped + // we do cache fully clipped edges + if (!r_leftclipped) + cacheoffset = FULLY_CLIPPED_CACHED | + (r_framecount & FRAMECOUNT_MASK); + return; + } + + // only point 0 is clipped + r_lastvertvalid = false; + + // we don't cache partially clipped edges + cacheoffset = 0x7FFFFFFF; + + f = d0 / (d0 - d1); + clipvert.position[0] = pv0->position[0] + + f * (pv1->position[0] - pv0->position[0]); + clipvert.position[1] = pv0->position[1] + + f * (pv1->position[1] - pv0->position[1]); + clipvert.position[2] = pv0->position[2] + + f * (pv1->position[2] - pv0->position[2]); + +//-- + { + if (!(d0_fxp)) + f_fxp=2<<29; + else { + f_fxp = (((d0_fxp - d1_fxp)<<7)/(d0_fxp)); //(25.7->18.14) / 25.7 = 25.7 + if (!f_fxp) f_fxp=2<<29; + } + + //f_fxp=(int)(4096.0/f); + + tmp = ((int)(pv0->position[0]*524288.0f)) + + (((((int)(pv1->position[0]*524288.0f)) - ((int)(pv0->position[0]*524288.0f)))/f_fxp)<<7); //13.19 / 25.7 = 20.12 + //if (!tmp) tmp=1; + clipvert.position[0]=tmp/524288.0f; + + tmp = ((int)(pv0->position[1]*524288.0f)) + + (((((int)(pv1->position[1]*524288.0f)) - ((int)(pv0->position[1]*524288.0f)))/f_fxp)<<7); //12.20 / 24.8 = 20.12 + //if (!tmp) tmp=1; + clipvert.position[1]=tmp/524288.0f; + + tmp = ((int)(pv0->position[2]*524288.0f)) + + (((((int)(pv1->position[2]*524288.0f)) - ((int)(pv0->position[2]*524288.0f)))/f_fxp)<<7); //12.20 / 24.8 = 20.12 + //if (!tmp) tmp=1; + clipvert.position[2]=tmp/524288.0f; + } + pv1->position[0]=((int)(pv1->position[0]*524288.0f))/524288.0f; + pv1->position[1]=((int)(pv1->position[1]*524288.0f))/524288.0f; + pv1->position[2]=((int)(pv1->position[2]*524288.0f))/524288.0f; + +////-- + + if (clip->leftedge) + { + r_leftclipped = true; + r_leftenter = clipvert; + } + else if (clip->rightedge) + { + r_rightclipped = true; + r_rightenter = clipvert; + } + + R_ClipEdge (&clipvert, pv1, clip->next); + return; + } + } while ((clip = clip->next) != NULL); + } + +// add the edge +#ifndef USE_PQ_OPT1 + R_EmitEdge (pv0, pv1); +#else + R_EmitEdge_fxp (pv0, pv1); +#endif +} + +// Yoda +#pragma ENABLE_OPTIMIZATION + +#endif // !id386 + + +/* +================ +R_EmitCachedEdge +================ +*/ +void R_EmitCachedEdge (void) +{ + edge_t *pedge_t; + + pedge_t = (edge_t *)((unsigned long)r_edges + r_pedge->cachededgeoffset); + + if (!pedge_t->surfs[0]) + pedge_t->surfs[0] = surface_p - surfaces; + else + pedge_t->surfs[1] = surface_p - surfaces; + + if (pedge_t->nearzi > r_nearzi) // for mipmap finding + r_nearzi = pedge_t->nearzi; + + r_emitted = 1; +} + +#ifdef USEFPM +void R_EmitCachedEdgeFPM (void) +{ + edge_FPM_t *pedge_t; + + pedge_t = (edge_FPM_t *)((unsigned long)r_edgesFPM + r_pedge->cachededgeoffset); + + if (!pedge_t->surfs[0]) + pedge_t->surfs[0] = surface_FPM_p - surfacesFPM; + else + pedge_t->surfs[1] = surface_FPM_p - surfacesFPM; + + if (pedge_t->nearzi > r_nearziFPM) // for mipmap finding + r_nearziFPM = pedge_t->nearzi; + + r_emitted = 1; +} +#endif //USEFPM + +/* +================ +R_RenderFace +================ +*/ +void R_RenderFace (msurface_t *fa, int clipflags) +{ + int i, lindex; + unsigned mask; + mplane_t *pplane; + float distinv; + vec3_t p_normal; + medge_t *pedges, tedge; + clipplane_t *pclip; +#ifdef USE_PQ_OPT2 + clipplane_fxp_t *pclip_fxp; +#endif + + // GpError("A",9); + +// skip out if no more surfs + if ((surface_p) >= surf_max) + { + r_outofsurfaces++; + return; + } + +// ditto if not enough edges left, or switch to auxedges if possible + if ((edge_p + fa->numedges + 4) >= edge_max) + { + r_outofedges += fa->numedges; + return; + } + + c_faceclip++; + +// set up clip planes + pclip = NULL; + + // GpError("B",9); + + for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1) + { + if (clipflags & mask) + { + view_clipplanes[i].next = pclip; + pclip = &view_clipplanes[i]; + } + } + +#ifdef USE_PQ_OPT2 + pclip_fxp = NULL; + + for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1) + { + if (clipflags & mask) + { + view_clipplanes_fxp[i].next = pclip_fxp; + pclip_fxp = &view_clipplanes_fxp[i]; + } + } +#endif + +// push the edges through + r_emitted = 0; + r_nearzi = 0; + r_nearzionly = false; + makeleftedge = makerightedge = false; + pedges = currententity->model->edges; + r_lastvertvalid = false; + + // GpError("C",9); + + for (i=0 ; inumedges ; i++) + { + lindex = currententity->model->surfedges[fa->firstedge + i]; + + if (lindex > 0) + { + r_pedge = &pedges[lindex]; + + // if the edge is cached, we can just reuse the edge + if (!insubmodel) + { + if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED) + { + if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) == + (unsigned int)r_framecount) + { + r_lastvertvalid = false; + continue; + } + } + else + { + if ((((unsigned long)edge_p - (unsigned long)r_edges) > + r_pedge->cachededgeoffset) && + (((edge_t *)((unsigned long)r_edges + + r_pedge->cachededgeoffset))->owner == r_pedge)) + { + R_EmitCachedEdge (); + r_lastvertvalid = false; + continue; + } + } + } + + // assume it's cacheable + cacheoffset = (byte *)edge_p - (byte *)r_edges; + r_leftclipped = r_rightclipped = false; +#ifndef USE_PQ_OPT2 + R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]], + &r_pcurrentvertbase[r_pedge->v[1]], + pclip); +#else + R_ClipEdge_fxp (&r_pcurrentvertbase_fxp[r_pedge->v[0]], + &r_pcurrentvertbase_fxp[r_pedge->v[1]], + pclip_fxp); +#endif + r_pedge->cachededgeoffset = cacheoffset; + + if (r_leftclipped) + makeleftedge = true; + if (r_rightclipped) + makerightedge = true; + r_lastvertvalid = true; + } + else + { + lindex = -lindex; + r_pedge = &pedges[lindex]; + // if the edge is cached, we can just reuse the edge + if (!insubmodel) + { + if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED) + { + if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) == + (unsigned int)r_framecount) + { + r_lastvertvalid = false; + continue; + } + } + else + { + // it's cached if the cached edge is valid and is owned + // by this medge_t + if ((((unsigned long)edge_p - (unsigned long)r_edges) > + r_pedge->cachededgeoffset) && + (((edge_t *)((unsigned long)r_edges + + r_pedge->cachededgeoffset))->owner == r_pedge)) + { + R_EmitCachedEdge (); + r_lastvertvalid = false; + continue; + } + } + } + + // assume it's cacheable + cacheoffset = (byte *)edge_p - (byte *)r_edges; + r_leftclipped = r_rightclipped = false; +#ifndef USE_PQ_OPT2 + R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]], + &r_pcurrentvertbase[r_pedge->v[0]], + pclip); +#else + R_ClipEdge_fxp (&r_pcurrentvertbase_fxp[r_pedge->v[1]], + &r_pcurrentvertbase_fxp[r_pedge->v[0]], + pclip_fxp); +#endif + r_pedge->cachededgeoffset = cacheoffset; + + if (r_leftclipped) + makeleftedge = true; + if (r_rightclipped) + makerightedge = true; + r_lastvertvalid = true; + } + } + + // GpError("D",9); + +// if there was a clip off the left edge, add that edge too +// FIXME: faster to do in screen space? +// FIXME: share clipped edges? + if (makeleftedge) + { + r_pedge = &tedge; + r_lastvertvalid = false; +#ifndef USE_PQ_OPT2 + R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next); +#else + R_ClipEdge_fxp (&r_leftexit_fxp, &r_leftenter_fxp, pclip_fxp->next); +#endif + } + + // GpError("E",9); + +// if there was a clip off the right edge, get the right r_nearzi + if (makerightedge) + { + r_pedge = &tedge; + r_lastvertvalid = false; + r_nearzionly = true; +#ifndef USE_PQ_OPT2 + R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next); +#else + R_ClipEdge_fxp (&r_rightexit_fxp, &r_rightenter_fxp, view_clipplanes_fxp[1].next); +#endif + } + + // GpError("F",9); + +// if no edges made it out, return without posting the surface + if (!r_emitted) + return; + + r_polycount++; + + surface_p->data = (void *)fa; + surface_p->nearzi = r_nearzi; + surface_p->flags = fa->flags; + surface_p->insubmodel = insubmodel; + surface_p->spanstate = 0; + surface_p->entity = currententity; + surface_p->key = r_currentkey++; + surface_p->spans = NULL; + + pplane = fa->plane; +// FIXME: cache this? + TransformVector (pplane->normal, p_normal); +// FIXME: cache this? + distinv = (float)(1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal))); + +#ifndef USE_PQ_OPT3 + surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv; + surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv; + surface_p->d_ziorigin = p_normal[2] * distinv - + xcenter * surface_p->d_zistepu - + ycenter * surface_p->d_zistepv; +#else + surface_p->d_zistepu_fxp=(int)(p_normal[0] * xscaleinv * distinv*4194304.0f); + surface_p->d_zistepv_fxp=(int)(-p_normal[1] * yscaleinv * distinv*4194304.0f); + surface_p->d_ziorigin_fxp=((int)(p_normal[2] * distinv * 4194304.0f)) - + ((int)(xcenter * surface_p->d_zistepu_fxp)) - + ((int)(ycenter * surface_p->d_zistepv_fxp)); +#endif +//JDC VectorCopy (r_worldmodelorg, surface_p->modelorg); + surface_p++; + // GpError("done",9); +} + + +/* +================ +R_RenderBmodelFace +================ +*/ +void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf) +{ + int i; + unsigned mask; + mplane_t *pplane; + float distinv; + vec3_t p_normal; + medge_t tedge; + clipplane_t *pclip; + + // skip out if no more surfs + if (surface_p >= surf_max) + { + r_outofsurfaces++; + return; + } + +// ditto if not enough edges left, or switch to auxedges if possible + if ((edge_p + psurf->numedges + 4) >= edge_max) + { + r_outofedges += psurf->numedges; + return; + } + + c_faceclip++; + +// this is a dummy to give the caching mechanism someplace to write to + r_pedge = &tedge; + +// set up clip planes + pclip = NULL; + + for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1) + { + if (r_clipflags & mask) + { + view_clipplanes[i].next = pclip; + pclip = &view_clipplanes[i]; + } + } + +// push the edges through + r_emitted = 0; + r_nearzi = 0; + r_nearzionly = false; + makeleftedge = makerightedge = false; +// FIXME: keep clipped bmodel edges in clockwise order so last vertex caching +// can be used? + r_lastvertvalid = false; + + for ( ; pedges ; pedges = pedges->pnext) + { + r_leftclipped = r_rightclipped = false; + R_ClipEdge (pedges->v[0], pedges->v[1], pclip); + + if (r_leftclipped) + makeleftedge = true; + if (r_rightclipped) + makerightedge = true; + } + +// if there was a clip off the left edge, add that edge too +// FIXME: faster to do in screen space? +// FIXME: share clipped edges? + if (makeleftedge) + { + r_pedge = &tedge; + R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next); + } + +// if there was a clip off the right edge, get the right r_nearzi + if (makerightedge) + { + r_pedge = &tedge; + r_nearzionly = true; + R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next); + } + +// if no edges made it out, return without posting the surface + if (!r_emitted) + return; + + r_polycount++; + + surface_p->data = (void *)psurf; + surface_p->nearzi = r_nearzi; + surface_p->flags = psurf->flags; + surface_p->insubmodel = true; + surface_p->spanstate = 0; + surface_p->entity = currententity; + surface_p->key = r_currentbkey; + surface_p->spans = NULL; + + pplane = psurf->plane; +// FIXME: cache this? + TransformVector (pplane->normal, p_normal); +// FIXME: cache this? + distinv = (float)(1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal))); + +#ifndef USE_PQ_OPT3 + surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv; + surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv; + surface_p->d_ziorigin = p_normal[2] * distinv - + xcenter * surface_p->d_zistepu - + ycenter * surface_p->d_zistepv; +#else + surface_p->d_zistepu_fxp=(int)(p_normal[0] * xscaleinv * distinv*4194304.0f); + surface_p->d_zistepv_fxp=(int)(-p_normal[1] * yscaleinv * distinv*4194304.0f); + surface_p->d_ziorigin_fxp=((int)(p_normal[2] * distinv * 4194304.0f)) - + ((int)(xcenter * surface_p->d_zistepu_fxp)) - + ((int)(ycenter * surface_p->d_zistepv_fxp)); +#endif + +//JDC VectorCopy (r_worldmodelorg, surface_p->modelorg); + surface_p++; +} + +/* +================ +R_RenderPoly +================ +*/ +void R_RenderPoly (msurface_t *fa, int clipflags) +{ + int i, lindex, lnumverts, s_axis, t_axis; + float dist, lastdist, lzi, scale, u, v, frac; + unsigned mask; + vec3_t local, transformed; + clipplane_t *pclip; + medge_t *pedges; + mplane_t *pplane; + mvertex_t verts[2][100]; //FIXME: do real number + polyvert_t pverts[100]; //FIXME: do real number, safely + int vertpage, newverts, newpage, lastvert; + qboolean visible; + +// FIXME: clean this up and make it faster +// FIXME: guard against running out of vertices + + s_axis = t_axis = 0; // keep compiler happy + +// set up clip planes + pclip = NULL; + + for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1) + { + if (clipflags & mask) + { + view_clipplanes[i].next = pclip; + pclip = &view_clipplanes[i]; + } + } + +// reconstruct the polygon +// FIXME: these should be precalculated and loaded off disk + pedges = currententity->model->edges; + lnumverts = fa->numedges; + vertpage = 0; + + for (i=0 ; imodel->surfedges[fa->firstedge + i]; + + if (lindex > 0) + { + r_pedge = &pedges[lindex]; + verts[0][i] = r_pcurrentvertbase[r_pedge->v[0]]; + } + else + { + r_pedge = &pedges[-lindex]; + verts[0][i] = r_pcurrentvertbase[r_pedge->v[1]]; + } + } + +// clip the polygon, done if not visible + while (pclip) + { + lastvert = lnumverts - 1; + lastdist = DotProduct (verts[vertpage][lastvert].position, + pclip->normal) - pclip->dist; + + visible = false; + newverts = 0; + newpage = vertpage ^ 1; + + for (i=0 ; inormal) - + pclip->dist; + + if ((lastdist > 0) != (dist > 0)) + { + frac = dist / (dist - lastdist); + verts[newpage][newverts].position[0] = + verts[vertpage][i].position[0] + + ((verts[vertpage][lastvert].position[0] - + verts[vertpage][i].position[0]) * frac); + verts[newpage][newverts].position[1] = + verts[vertpage][i].position[1] + + ((verts[vertpage][lastvert].position[1] - + verts[vertpage][i].position[1]) * frac); + verts[newpage][newverts].position[2] = + verts[vertpage][i].position[2] + + ((verts[vertpage][lastvert].position[2] - + verts[vertpage][i].position[2]) * frac); + newverts++; + } + + if (dist >= 0) + { + verts[newpage][newverts] = verts[vertpage][i]; + newverts++; + visible = true; + } + + lastvert = i; + lastdist = dist; + } + + if (!visible || (newverts < 3)) + return; + + lnumverts = newverts; + vertpage ^= 1; + pclip = pclip->next; + } + +// transform and project, remembering the z values at the vertices and +// r_nearzi, and extract the s and t coordinates at the vertices + pplane = fa->plane; + switch (pplane->type) + { + case PLANE_X: + case PLANE_ANYX: + s_axis = 1; + t_axis = 2; + break; + case PLANE_Y: + case PLANE_ANYY: + s_axis = 0; + t_axis = 2; + break; + case PLANE_Z: + case PLANE_ANYZ: + s_axis = 0; + t_axis = 1; + break; + } + + r_nearzi = 0; + + for (i=0 ; i r_nearzi) // for mipmap finding + r_nearzi = lzi; + + // FIXME: build x/yscale into transform? + scale = xscale * lzi; + u = (xcenter + scale*transformed[0]); + if (u < r_refdef.fvrectx_adj) + u = r_refdef.fvrectx_adj; + if (u > r_refdef.fvrectright_adj) + u = r_refdef.fvrectright_adj; + + scale = yscale * lzi; + v = (ycenter - scale*transformed[1]); + if (v < r_refdef.fvrecty_adj) + v = r_refdef.fvrecty_adj; + if (v > r_refdef.fvrectbottom_adj) + v = r_refdef.fvrectbottom_adj; + + pverts[i].u = u; + pverts[i].v = v; + pverts[i].zi = lzi; + pverts[i].s = verts[vertpage][i].position[s_axis]; + pverts[i].t = verts[vertpage][i].position[t_axis]; + } + +// build the polygon descriptor, including fa, r_nearzi, and u, v, s, t, and z +// for each vertex + r_polydesc.numverts = lnumverts; + r_polydesc.nearzi = r_nearzi; + r_polydesc.pcurrentface = fa; + r_polydesc.pverts = pverts; + +// draw the polygon + D_DrawPoly (); +} + + +/* +================ +R_ZDrawSubmodelPolys +================ +*/ +void R_ZDrawSubmodelPolys (model_t *pmodel) +{ + int i, numsurfaces; + msurface_t *psurf; + float dot; + mplane_t *pplane; + + psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; + numsurfaces = pmodel->nummodelsurfaces; + + for (i=0 ; iplane; + + dot = DotProduct (modelorg, pplane->normal) - pplane->dist; + + // draw the polygon + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + // FIXME: use bounding-box-based frustum clipping info? + R_RenderPoly (psurf, 15); + } + } +} + +#ifdef USEFPM +void R_ZDrawSubmodelPolysFPM (model_FPM_t *pmodel) +{ + int i, numsurfaces; + msurface_FPM_t *psurf; + fixedpoint_t dot; + mplane_FPM_t *pplane; + + psurf = &pmodel->surfaces[pmodel->firstmodelsurface]; + numsurfaces = pmodel->nummodelsurfaces; + + for (i=0 ; iplane; + + dot = FPM_SUB(DotProductFPM (modelorgFPM, pplane->normal), pplane->dist); + + // draw the polygon + if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || + (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) + { + // FIXME: use bounding-box-based frustum clipping info? + // R_RenderPolyFPM (psurf, 15); // FPM doesn't exist + R_RenderPoly (psurf, 15); + } + } +} +#endif //USEFPM diff --git a/project/jni/application/quake/source/r_edge.c b/project/jni/application/quake/source/r_edge.c new file mode 100644 index 000000000..7a41b115d --- /dev/null +++ b/project/jni/application/quake/source/r_edge.c @@ -0,0 +1,1457 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_edge.c + +#include "quakedef.h" +#include "r_local.h" + +#if 0 +// FIXME +the complex cases add new polys on most lines, so dont optimize for keeping them the same +have multiple free span lists to try to get better coherence? +low depth complexity -- 1 to 3 or so + +this breaks spans at every edge, even hidden ones (bad) + +have a sentinal at both ends? +#endif + + +edge_t *auxedges; +edge_t *r_edges, *edge_p, *edge_max; + +surf_t *surfaces, *surface_p, *surf_max; + +// surfaces are generated in back to front order by the bsp, so if a surf +// pointer is greater than another one, it should be drawn in front +// surfaces[1] is the background, and is used as the active surface stack + +edge_t *newedges[MAXHEIGHT]; +edge_t *removeedges[MAXHEIGHT]; + +espan_t *span_p, *max_span_p; + +int r_currentkey; + +extern int screenwidth; + +int current_iv; + +int edge_head_u_shift20, edge_tail_u_shift20; + +static void (*pdrawfunc)(void); + +edge_t edge_head; +edge_t edge_tail; +edge_t edge_aftertail; +edge_t edge_sentinel; + +float fv; + +void R_GenerateSpans (void); +void R_GenerateSpansBackward (void); + + +void R_LeadingEdge (edge_t *edge); +void R_LeadingEdgeBackwards (edge_t *edge); +void R_TrailingEdge (surf_t *surf, edge_t *edge); + +#ifdef USEFPM +edge_FPM_t *auxedgesFPM; +edge_FPM_t *r_edgesFPM, *edge_FPM_p, *edge_maxFPM; +surf_FPM_t *surfacesFPM, *surface_FPM_p, *surf_maxFPM; +edge_FPM_t *newedgesFPM[MAXHEIGHT]; +edge_FPM_t *removeedgesFPM[MAXHEIGHT]; +espan_t *span_FPM_p, *max_span_FPM_p; +edge_FPM_t edge_headFPM; +edge_FPM_t edge_tailFPM; +edge_FPM_t edge_aftertailFPM; +edge_FPM_t edge_sentinelFPM; + + +void R_GenerateSpansFPM (void); +void R_GenerateSpansBackwardFPM (void); +#endif //USEFPM + +//============================================================================= + + +/* +============== +R_DrawCulledPolys +============== +*/ +void R_DrawCulledPolys (void) +{ + surf_t *s; + msurface_t *pface; + + currententity = &cl_entities[0]; + + if (r_worldpolysbacktofront) + { + for (s=surface_p-1 ; s>&surfaces[1] ; s--) + { + if (!s->spans) + continue; + + if (!(s->flags & SURF_DRAWBACKGROUND)) + { + pface = (msurface_t *)s->data; + R_RenderPoly (pface, 15); + } + } + } + else + { + for (s = &surfaces[1] ; sspans) + continue; + + if (!(s->flags & SURF_DRAWBACKGROUND)) + { + pface = (msurface_t *)s->data; + R_RenderPoly (pface, 15); + } + } + } +} + +#ifdef USEFPM +void R_DrawCulledPolysFPM (void) +{ + surf_FPM_t *s; + msurface_FPM_t *pface; + + currententityFPM = &cl_entitiesFPM[0]; + + if (r_worldpolysbacktofront) + { + for (s=surface_FPM_p-1 ; s>&surfacesFPM[1] ; s--) + { + if (!s->spans) + continue; + + if (!(s->flags & SURF_DRAWBACKGROUND)) + { + pface = (msurface_FPM_t *)s->data; + // R_RenderPolyFPM (pface, 15); // FPM doesn't exist + R_RenderPoly (pface, 15); + } + } + } + else + { + for (s = &surfacesFPM[1] ; sspans) + continue; + + if (!(s->flags & SURF_DRAWBACKGROUND)) + { + pface = (msurface_FPM_t *)s->data; + //R_RenderPolyFPM (pface, 15); // FPM doesn't exist + R_RenderPoly (pface, 15); + } + } + } +} +#endif //USEFPM + +/* +============== +R_BeginEdgeFrame +============== +*/ +void R_BeginEdgeFrame (void) +{ + int v; + + edge_p = r_edges; + + edge_max = &r_edges[r_numallocatededges]; + + surface_p = &surfaces[2]; // background is surface 1, + // surface 0 is a dummy + surfaces[1].spans = NULL; // no background spans yet + surfaces[1].flags = SURF_DRAWBACKGROUND; + +// put the background behind everything in the world + if (r_draworder.value) + { + pdrawfunc = R_GenerateSpansBackward; + surfaces[1].key = 0; + r_currentkey = 1; + } + else + { + pdrawfunc = R_GenerateSpans; + surfaces[1].key = 0x7FFFFFFF; + r_currentkey = 0; + } + +// FIXME: set with memset + for (v=r_refdef.vrect.y ; vnext; +edgesearch: + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + goto edgesearch; + + // insert edgestoadd before edgelist +addedge: + edgestoadd->next = edgelist; + edgestoadd->prev = edgelist->prev; + edgelist->prev->next = edgestoadd; + edgelist->prev = edgestoadd; + } while ((edgestoadd = next_edge) != NULL); +} + +#ifdef USEFPM +void R_InsertNewEdgesFPM (edge_FPM_t *edgestoadd, edge_FPM_t *edgelist) +{ + edge_FPM_t *next_edge; + + do + { + next_edge = edgestoadd->next; +edgesearch: + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + if (edgelist->u >= edgestoadd->u) + goto addedge; + edgelist=edgelist->next; + goto edgesearch; + + // insert edgestoadd before edgelist +addedge: + edgestoadd->next = edgelist; + edgestoadd->prev = edgelist->prev; + edgelist->prev->next = edgestoadd; + edgelist->prev = edgestoadd; + } while ((edgestoadd = next_edge) != NULL); +} +#endif //USEFPM +#endif // !id386 + + +#if !id386 + +/* +============== +R_RemoveEdges +============== +*/ +void R_RemoveEdges (edge_t *pedge) +{ + + do + { + pedge->next->prev = pedge->prev; + pedge->prev->next = pedge->next; + } while ((pedge = pedge->nextremove) != NULL); +} + +#ifdef USEFPM +void R_RemoveEdgesFPM (edge_FPM_t *pedge) +{ + + do + { + pedge->next->prev = pedge->prev; + pedge->prev->next = pedge->next; + } while ((pedge = pedge->nextremove) != NULL); +} +#endif //USEFPM +#endif // !id386 + + +#if !id386 + +/* +============== +R_StepActiveU +============== +*/ +void R_StepActiveU (edge_t *pedge) +{ + edge_t *pnext_edge, *pwedge; + + while (1) + { +nextedge: + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + goto nextedge; + +pushback: + if (pedge == &edge_aftertail) + return; + + // push it back to keep it sorted + pnext_edge = pedge->next; + + // pull the edge out of the edge list + pedge->next->prev = pedge->prev; + pedge->prev->next = pedge->next; + + // find out where the edge goes in the edge list + pwedge = pedge->prev->prev; + + while (pwedge->u > pedge->u) + { + pwedge = pwedge->prev; + } + + // put the edge back into the edge list + pedge->next = pwedge->next; + pedge->prev = pwedge; + pedge->next->prev = pedge; + pwedge->next = pedge; + + pedge = pnext_edge; + if (pedge == &edge_tail) + return; + } +} + +#ifdef USEFPM +void R_StepActiveUFPM (edge_FPM_t *pedge) +{ + edge_FPM_t *pnext_edge, *pwedge; + + while (1) + { +nextedge: + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + pedge->u += pedge->u_step; + if (pedge->u < pedge->prev->u) + goto pushback; + pedge = pedge->next; + + goto nextedge; + +pushback: + if (pedge == &edge_aftertailFPM) + return; + + // push it back to keep it sorted + pnext_edge = pedge->next; + + // pull the edge out of the edge list + pedge->next->prev = pedge->prev; + pedge->prev->next = pedge->next; + + // find out where the edge goes in the edge list + pwedge = pedge->prev->prev; + + while (pwedge->u > pedge->u) + { + pwedge = pwedge->prev; + } + + // put the edge back into the edge list + pedge->next = pwedge->next; + pedge->prev = pwedge; + pedge->next->prev = pedge; + pwedge->next = pedge; + + pedge = pnext_edge; + if (pedge == &edge_tailFPM) + return; + } +} +#endif //USEFPM +#endif // !id386 + + +/* +============== +R_CleanupSpan +============== +*/ +void R_CleanupSpan () +{ + surf_t *surf; + int iu; + espan_t *span; + +// now that we've reached the right edge of the screen, we're done with any +// unfinished surfaces, so emit a span for whatever's on top + surf = surfaces[1].next; + iu = edge_tail_u_shift20; + if (iu > surf->last_u) + { + span = span_p++; + span->u = surf->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf->spans; + surf->spans = span; + } + +// reset spanstate for all surfaces in the surface stack + do + { + surf->spanstate = 0; + surf = surf->next; + } while (surf != &surfaces[1]); +} + +#ifdef USEFPM +void R_CleanupSpanFPM () +{ + surf_FPM_t *surf; + int iu; + espan_t *span; + +// now that we've reached the right edge of the screen, we're done with any +// unfinished surfaces, so emit a span for whatever's on top + surf = surfacesFPM[1].next; + iu = edge_tail_u_shift20; + if (iu > surf->last_u) + { + span = span_p++; + span->u = surf->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf->spans; + surf->spans = span; + } + +// reset spanstate for all surfaces in the surface stack + do + { + surf->spanstate = 0; + surf = surf->next; + } while (surf != &surfacesFPM[1]); +} +#endif //USEFPM + +/* +============== +R_LeadingEdgeBackwards +============== +*/ +void R_LeadingEdgeBackwards (edge_t *edge) +{ + espan_t *span; + surf_t *surf, *surf2; + int iu; + +// it's adding a new surface in, so find the correct place + surf = &surfaces[edge->surfs[1]]; + +// don't start a span if this is an inverted span, with the end +// edge preceding the start edge (that is, we've already seen the +// end edge) + if (++surf->spanstate == 1) + { + surf2 = surfaces[1].next; + + if (surf->key > surf2->key) + goto newtop; + + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (surf->insubmodel && (surf->key == surf2->key)) + { + // must be two bmodels in the same leaf; don't care, because they'll + // never be farthest anyway + goto newtop; + } + +continue_search: + + do + { + surf2 = surf2->next; + } while (surf->key < surf2->key); + + if (surf->key == surf2->key) + { + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (!surf->insubmodel) + goto continue_search; + + // must be two bmodels in the same leaf; don't care which is really + // in front, because they'll never be farthest anyway + } + + goto gotposition; + +newtop: + // emit a span (obscures current top) + iu = edge->u >> 20; + + if (iu > surf2->last_u) + { + span = span_p++; + span->u = surf2->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf2->spans; + surf2->spans = span; + } + + // set last_u on the new span + surf->last_u = iu; + +gotposition: + // insert before surf2 + surf->next = surf2; + surf->prev = surf2->prev; + surf2->prev->next = surf; + surf2->prev = surf; + } +} + +#ifdef USEFPM +void R_LeadingEdgeBackwardsFPM (edge_FPM_t *edge) +{ + espan_t *span; + surf_FPM_t *surf, *surf2; + int iu; + +// it's adding a new surface in, so find the correct place + surf = &surfacesFPM[edge->surfs[1]]; + +// don't start a span if this is an inverted span, with the end +// edge preceding the start edge (that is, we've already seen the +// end edge) + if (++surf->spanstate == 1) + { + surf2 = surfacesFPM[1].next; + + if (surf->key > surf2->key) + goto newtop; + + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (surf->insubmodel && (surf->key == surf2->key)) + { + // must be two bmodels in the same leaf; don't care, because they'll + // never be farthest anyway + goto newtop; + } + +continue_search: + + do + { + surf2 = surf2->next; + } while (surf->key < surf2->key); + + if (surf->key == surf2->key) + { + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (!surf->insubmodel) + goto continue_search; + + // must be two bmodels in the same leaf; don't care which is really + // in front, because they'll never be farthest anyway + } + + goto gotposition; + +newtop: + // emit a span (obscures current top) + iu = edge->u >> 20; + + if (iu > surf2->last_u) + { + span = span_p++; + span->u = surf2->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf2->spans; + surf2->spans = span; + } + + // set last_u on the new span + surf->last_u = iu; + +gotposition: + // insert before surf2 + surf->next = surf2; + surf->prev = surf2->prev; + surf2->prev->next = surf; + surf2->prev = surf; + } +} +#endif //USEFPM + +/* +============== +R_TrailingEdge +============== +*/ +void R_TrailingEdge (surf_t *surf, edge_t *edge) +{ + espan_t *span; + int iu; + +// don't generate a span if this is an inverted span, with the end +// edge preceding the start edge (that is, we haven't seen the +// start edge yet) + if (--surf->spanstate == 0) + { + if (surf->insubmodel) + r_bmodelactive--; + + if (surf == surfaces[1].next) + { + // emit a span (current top going away) + iu = edge->u >> 20; + if (iu > surf->last_u) + { + span = span_p++; + span->u = surf->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf->spans; + surf->spans = span; + } + + // set last_u on the surface below + surf->next->last_u = iu; + } + + surf->prev->next = surf->next; + surf->next->prev = surf->prev; + } +} + +#ifdef USEFPM +void R_TrailingEdgeFPM (surf_FPM_t *surf, edge_FPM_t *edge) +{ + espan_t *span; + int iu; + +// don't generate a span if this is an inverted span, with the end +// edge preceding the start edge (that is, we haven't seen the +// start edge yet) + if (--surf->spanstate == 0) + { + if (surf->insubmodel) + r_bmodelactive--; + + if (surf == surfacesFPM[1].next) + { + // emit a span (current top going away) + iu = edge->u >> 20; + if (iu > surf->last_u) + { + span = span_p++; + span->u = surf->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf->spans; + surf->spans = span; + } + + // set last_u on the surface below + surf->next->last_u = iu; + } + + surf->prev->next = surf->next; + surf->next->prev = surf->prev; + } +} +#endif //USEFPM + +#if !id386 + +/* +============== +R_LeadingEdge +============== +*/ +void R_LeadingEdge (edge_t *edge) +{ + espan_t *span; + surf_t *surf, *surf2; + int iu; +#ifndef USE_PQ_OPT3 + double fu, newzi, testzi, newzitop, newzibottom; +#else + int fu, newzi, testzi, newzitop, newzibottom; +#endif + + if (edge->surfs[1]) + { + // it's adding a new surface in, so find the correct place + surf = &surfaces[edge->surfs[1]]; + + // don't start a span if this is an inverted span, with the end + // edge preceding the start edge (that is, we've already seen the + // end edge) + if (++surf->spanstate == 1) + { + if (surf->insubmodel) + r_bmodelactive++; + + surf2 = surfaces[1].next; + + if (surf->key < surf2->key) + goto newtop; + + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (surf->insubmodel && (surf->key == surf2->key)) + { + // must be two bmodels in the same leaf; sort on 1/z +#ifndef USE_PQ_OPT3 + fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000); + newzi = surf->d_ziorigin + fv*surf->d_zistepv + + fu*surf->d_zistepu; + newzibottom = newzi * 0.99; + + testzi = surf2->d_ziorigin + fv*surf2->d_zistepv + + fu*surf2->d_zistepu; + + if (newzibottom >= testzi) + { + goto newtop; + } + + newzitop = newzi * 1.01; + + if (newzitop >= testzi) + { + if (surf->d_zistepu >= surf2->d_zistepu) + { + goto newtop; + } + } +#else/* + fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000); + newzi = surf->d_ziorigin + fv*surf->d_zistepv + + fu*surf->d_zistepu; + newzibottom = newzi * 0.99; + + testzi = surf2->d_ziorigin + fv*surf2->d_zistepv + + fu*surf2->d_zistepu; + + if (newzibottom >= testzi) + { + goto newtop; + } + + newzitop = newzi * 1.01; + if (newzitop >= testzi) + { + if (surf->d_zistepu >= surf2->d_zistepu) + { + goto newtop; + } + }*/ +#endif + + } +continue_search: + + do + { + surf2 = surf2->next; + } while (surf->key > surf2->key); + + if (surf->key == surf2->key) + { + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (!surf->insubmodel) + goto continue_search; +/* + // must be two bmodels in the same leaf; sort on 1/z + fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000); + newzi = surf->d_ziorigin + fv*surf->d_zistepv + + fu*surf->d_zistepu; + newzibottom = newzi * 0.99; + + testzi = surf2->d_ziorigin + fv*surf2->d_zistepv + + fu*surf2->d_zistepu; + + if (newzibottom >= testzi) + { + goto gotposition; + } + + newzitop = newzi * 1.01; + if (newzitop >= testzi) + { + if (surf->d_zistepu >= surf2->d_zistepu) + { + goto gotposition; + } + } +*/ + goto continue_search; + } + + goto gotposition; + +newtop: + // emit a span (obscures current top) + iu = edge->u >> 20; + + if (iu > surf2->last_u) + { + span = span_p++; + span->u = surf2->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf2->spans; + surf2->spans = span; + } + + // set last_u on the new span + surf->last_u = iu; + +gotposition: + // insert before surf2 + surf->next = surf2; + surf->prev = surf2->prev; + surf2->prev->next = surf; + surf2->prev = surf; + } + } +} + +#ifdef USEFPM +void R_LeadingEdgeFPM (edge_FPM_t *edge) +{ + espan_t *span; + surf_FPM_t *surf, *surf2; + int iu; + double fu, newzi, testzi, newzitop, newzibottom; + + //Dan: TODO: this func uses double calculations to determine the inclusion of edges. + //These routines also use a fixed16 type, in the struct edge_FPM_t. Some thought will + //have to go into converting them to fixedpoint_t. I'm trying to blow this thing out... + + if (edge->surfs[1]) + { + // it's adding a new surface in, so find the correct place + surf = &surfacesFPM[edge->surfs[1]]; + + // don't start a span if this is an inverted span, with the end + // edge preceding the start edge (that is, we've already seen the + // end edge) + if (++surf->spanstate == 1) + { + if (surf->insubmodel) + r_bmodelactive++; + + surf2 = surfacesFPM[1].next; + + if (surf->key < surf2->key) + goto newtop; + + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (surf->insubmodel && (surf->key == surf2->key)) + { + // must be two bmodels in the same leaf; sort on 1/z + fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000); + newzi = surf->d_ziorigin + fv*surf->d_zistepv + + fu*surf->d_zistepu; + newzibottom = newzi * 0.99; + + testzi = surf2->d_ziorigin + fv*surf2->d_zistepv + + fu*surf2->d_zistepu; + + if (newzibottom >= testzi) + { + goto newtop; + } + + newzitop = newzi * 1.01; + if (newzitop >= testzi) + { + if (surf->d_zistepu >= surf2->d_zistepu) + { + goto newtop; + } + } + } + +continue_search: + + do + { + surf2 = surf2->next; + } while (surf->key > surf2->key); + + if (surf->key == surf2->key) + { + // if it's two surfaces on the same plane, the one that's already + // active is in front, so keep going unless it's a bmodel + if (!surf->insubmodel) + goto continue_search; + + // must be two bmodels in the same leaf; sort on 1/z + fu = (float)(edge->u - 0xFFFFF) * (1.0 / 0x100000); + newzi = surf->d_ziorigin + fv*surf->d_zistepv + + fu*surf->d_zistepu; + newzibottom = newzi * 0.99; + + testzi = surf2->d_ziorigin + fv*surf2->d_zistepv + + fu*surf2->d_zistepu; + + if (newzibottom >= testzi) + { + goto gotposition; + } + + newzitop = newzi * 1.01; + if (newzitop >= testzi) + { + if (surf->d_zistepu >= surf2->d_zistepu) + { + goto gotposition; + } + } + + goto continue_search; + } + + goto gotposition; + +newtop: + // emit a span (obscures current top) + iu = edge->u >> 20; + + if (iu > surf2->last_u) + { + span = span_p++; + span->u = surf2->last_u; + span->count = iu - span->u; + span->v = current_iv; + span->pnext = surf2->spans; + surf2->spans = span; + } + + // set last_u on the new span + surf->last_u = iu; + +gotposition: + // insert before surf2 + surf->next = surf2; + surf->prev = surf2->prev; + surf2->prev->next = surf; + surf2->prev = surf; + } + } +} +#endif //USEFPM + +/* +============== +R_GenerateSpans +============== +*/ +void R_GenerateSpans (void) +{ + edge_t *edge; + surf_t *surf; + + r_bmodelactive = 0; + +// clear active surfaces to just the background surface + surfaces[1].next = surfaces[1].prev = &surfaces[1]; + surfaces[1].last_u = edge_head_u_shift20; + +// generate spans + for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next) + { + if (edge->surfs[0]) + { + // it has a left surface, so a surface is going away for this span + surf = &surfaces[edge->surfs[0]]; + + R_TrailingEdge (surf, edge); + + if (!edge->surfs[1]) + continue; + } + + R_LeadingEdge (edge); + } + + R_CleanupSpan (); +} + +#ifdef USEFPM +void R_GenerateSpansFPM (void) +{ + edge_FPM_t *edge; + surf_FPM_t *surf; + + r_bmodelactive = 0; + +// clear active surfaces to just the background surface + surfacesFPM[1].next = surfacesFPM[1].prev = &surfacesFPM[1]; + surfacesFPM[1].last_u = edge_head_u_shift20; + +// generate spans + for (edge=edge_headFPM.next ; edge != &edge_tailFPM; edge=edge->next) + { + if (edge->surfs[0]) + { + // it has a left surface, so a surface is going away for this span + surf = &surfacesFPM[edge->surfs[0]]; + + R_TrailingEdgeFPM (surf, edge); + + if (!edge->surfs[1]) + continue; + } + + R_LeadingEdgeFPM (edge); + } + + R_CleanupSpanFPM (); +} +#endif //USEFPM +#endif // !id386 + + +/* +============== +R_GenerateSpansBackward +============== +*/ +void R_GenerateSpansBackward (void) +{ + edge_t *edge; + + r_bmodelactive = 0; + +// clear active surfaces to just the background surface + surfaces[1].next = surfaces[1].prev = &surfaces[1]; + surfaces[1].last_u = edge_head_u_shift20; + +// generate spans + for (edge=edge_head.next ; edge != &edge_tail; edge=edge->next) + { + if (edge->surfs[0]) + R_TrailingEdge (&surfaces[edge->surfs[0]], edge); + + if (edge->surfs[1]) + R_LeadingEdgeBackwards (edge); + } + + R_CleanupSpan (); +} + +#ifdef USEFPM +void R_GenerateSpansBackwardFPM (void) +{ + edge_FPM_t *edge; + + r_bmodelactive = 0; + +// clear active surfaces to just the background surface + surfacesFPM[1].next = surfacesFPM[1].prev = &surfacesFPM[1]; + surfacesFPM[1].last_u = edge_head_u_shift20; + +// generate spans + for (edge=edge_headFPM.next ; edge != &edge_tailFPM; edge=edge->next) + { + if (edge->surfs[0]) + R_TrailingEdgeFPM (&surfacesFPM[edge->surfs[0]], edge); + + if (edge->surfs[1]) + R_LeadingEdgeBackwardsFPM (edge); + } + + R_CleanupSpan (); +} +#endif //USEFPM + + +//extern byte *basespans; +//byte basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE]; + +/* +============== +R_ScanEdges + +Input: +newedges[] array + this has links to edges, which have links to surfaces + +Output: +Each surface has a linked list of its visible spans +============== +*/ + +void R_ScanEdges (void) +{ + byte basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE]; + int iv, bottom; + //byte *basespans; + espan_t *basespan_p; + surf_t *s; + + //basespans = malloc(MAXSPANS*sizeof(espan_t)+CACHE_SIZE); + + + basespan_p = (espan_t *) ((long)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + max_span_p = &basespan_p[MAXSPANS - r_refdef.vrect.width]; + + span_p = basespan_p; + +// clear active edges to just the background edges around the whole screen +// FIXME: most of this only needs to be set up once + edge_head.u = r_refdef.vrect.x << 20; + edge_head_u_shift20 = edge_head.u >> 20; + edge_head.u_step = 0; + edge_head.prev = NULL; + edge_head.next = &edge_tail; + edge_head.surfs[0] = 0; + edge_head.surfs[1] = 1; + + edge_tail.u = (r_refdef.vrectright << 20) + 0xFFFFF; + edge_tail_u_shift20 = edge_tail.u >> 20; + edge_tail.u_step = 0; + edge_tail.prev = &edge_head; + edge_tail.next = &edge_aftertail; + edge_tail.surfs[0] = 1; + edge_tail.surfs[1] = 0; + + edge_aftertail.u = -1; // force a move + edge_aftertail.u_step = 0; + edge_aftertail.next = &edge_sentinel; + edge_aftertail.prev = &edge_tail; + +// FIXME: do we need this now that we clamp x in r_draw.c? + edge_sentinel.u = 2000 << 24; // make sure nothing sorts past this + edge_sentinel.prev = &edge_aftertail; + + +// +// process all scan lines +// + bottom = r_refdef.vrectbottom - 1; + + for (iv=r_refdef.vrect.y ; iv= max_span_p) + { + // VID_UnlockBuffer (); + S_ExtraUpdate (); // don't let sound get messed up if going slow + // VID_LockBuffer (); + + if (r_drawculledpolys) + { + R_DrawCulledPolys (); + } + else + { + D_DrawSurfaces (); + } + + // clear the surface span pointers + for (s = &surfaces[1] ; sspans = NULL; + + span_p = basespan_p; + } + + if (removeedges[iv]) + R_RemoveEdges (removeedges[iv]); + + if (edge_head.next != &edge_tail) + R_StepActiveU (edge_head.next); + } + + +// do the last scan (no need to step or sort or remove on the last scan) + + current_iv = iv; + fv = (float)iv; + +// mark that the head (background start) span is pre-included + surfaces[1].spanstate = 1; + + if (newedges[iv]) + R_InsertNewEdges (newedges[iv], edge_head.next); + + (*pdrawfunc) (); + + + +// draw whatever's left in the span list + if (r_drawculledpolys) { + R_DrawCulledPolys (); + } + else { + D_DrawSurfaces (); + } + + // free(basespans); + + +} + +#ifdef USEFPM +void R_ScanEdgesFPM (void) +{ +byte basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE]; + int iv, bottom; + // byte basespans[MAXSPANS*sizeof(espan_t)+CACHE_SIZE]; + espan_t *basespan_p; + surf_FPM_t *s; + + basespan_p = (espan_t *) + ((long)(basespans + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + max_span_p = &basespan_p[MAXSPANS - r_refdefFPM.vrect.width]; + + span_p = basespan_p; + +// clear active edges to just the background edges around the whole screen +// FIXME: most of this only needs to be set up once + edge_headFPM.u = r_refdefFPM.vrect.x << 20; + edge_head_u_shift20 = edge_headFPM.u >> 20; + edge_headFPM.u_step = 0; + edge_headFPM.prev = NULL; + edge_headFPM.next = &edge_tailFPM; + edge_headFPM.surfs[0] = 0; + edge_headFPM.surfs[1] = 1; + + edge_tailFPM.u = (r_refdefFPM.vrectright << 20) + 0xFFFFF; + edge_tail_u_shift20 = edge_tailFPM.u >> 20; + edge_tailFPM.u_step = 0; + edge_tailFPM.prev = &edge_headFPM; + edge_tailFPM.next = &edge_aftertailFPM; + edge_tailFPM.surfs[0] = 1; + edge_tailFPM.surfs[1] = 0; + + edge_aftertailFPM.u = -1; // force a move + edge_aftertailFPM.u_step = 0; + edge_aftertailFPM.next = &edge_sentinelFPM; + edge_aftertailFPM.prev = &edge_tailFPM; + +// FIXME: do we need this now that we clamp x in r_draw.c? + edge_sentinelFPM.u = 2000 << 24; // make sure nothing sorts past this + edge_sentinelFPM.prev = &edge_aftertailFPM; + +// +// process all scan lines +// + bottom = r_refdefFPM.vrectbottom - 1; + + for (iv=r_refdefFPM.vrect.y ; iv= max_span_p) + { + VID_UnlockBuffer (); + S_ExtraUpdate (); // don't let sound get messed up if going slow + VID_LockBuffer (); + + if (r_drawculledpolys) + { + R_DrawCulledPolysFPM (); + } + else + { + //D_DrawSurfacesFPM (); // FPM doesn't exist + D_DrawSurfaces (); + } + + // clear the surface span pointers + for (s = &surfacesFPM[1] ; sspans = NULL; + + span_FPM_p = basespan_p; + } + + if (removeedgesFPM[iv]) + R_RemoveEdgesFPM (removeedgesFPM[iv]); + + if (edge_headFPM.next != &edge_tailFPM) + R_StepActiveUFPM (edge_headFPM.next); + } + +// do the last scan (no need to step or sort or remove on the last scan) + + current_iv = iv; + fv = (float)iv; + +// mark that the head (background start) span is pre-included + surfacesFPM[1].spanstate = 1; + + if (newedgesFPM[iv]) + R_InsertNewEdgesFPM (newedgesFPM[iv], edge_headFPM.next); + + (*pdrawfunc) (); + +// draw whatever's left in the span list + if (r_drawculledpolys) + R_DrawCulledPolysFPM (); + else + //D_DrawSurfacesFPM (); // FPM doesn't exist + D_DrawSurfaces (); +} +#endif //USEFPM + diff --git a/project/jni/application/quake/source/r_efrag.c b/project/jni/application/quake/source/r_efrag.c new file mode 100644 index 000000000..bd5463d4a --- /dev/null +++ b/project/jni/application/quake/source/r_efrag.c @@ -0,0 +1,489 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_efrag.c + +#include "quakedef.h" +#include "r_local.h" + +mnode_t *r_pefragtopnode; + +#ifdef USEFPM +mnode_FPM_t *r_pefragtopnodeFPM; +#endif //USEFPM + +//=========================================================================== + +/* +=============================================================================== + + ENTITY FRAGMENT FUNCTIONS + +=============================================================================== +*/ + +efrag_t **lastlink; + +vec3_t r_emins, r_emaxs; + +entity_t *r_addent; + +#ifdef USEFPM +efrag_FPM_t **lastlinkFPM; +vec3_FPM_t r_eminsFPM, r_emaxsFPM; +entity_FPM_t *r_addentFPM; +#endif //USEFPM + +/* +================ +R_RemoveEfrags + +Call when removing an object from the world or moving it to another position +================ +*/ +void R_RemoveEfrags (entity_t *ent) +{ + efrag_t *ef, *old, *walk, **prev; + + ef = ent->efrag; + + while (ef) + { + prev = &ef->leaf->efrags; + while (1) + { + walk = *prev; + if (!walk) + break; + if (walk == ef) + { // remove this fragment + *prev = ef->leafnext; + break; + } + else + prev = &walk->leafnext; + } + + old = ef; + ef = ef->entnext; + + // put it on the free list + old->entnext = cl.free_efrags; + cl.free_efrags = old; + } + + ent->efrag = NULL; +} + +#ifdef USEFPM +void R_RemoveEfragsFPM (entity_FPM_t *ent) +{ + efrag_FPM_t *ef, *old, *walk, **prev; + + ef = ent->efrag; + + while (ef) + { + prev = &ef->leaf->efrags; + while (1) + { + walk = *prev; + if (!walk) + break; + if (walk == ef) + { // remove this fragment + *prev = ef->leafnext; + break; + } + else + prev = &walk->leafnext; + } + + old = ef; + ef = ef->entnext; + + // put it on the free list + old->entnext = clFPM.free_efrags; + clFPM.free_efrags = old; + } + + ent->efrag = NULL; +} +#endif //USEFPM + +/* +=================== +R_SplitEntityOnNode +=================== +*/ +void R_SplitEntityOnNode (mnode_t *node) +{ + efrag_t *ef; + mplane_t *splitplane; + mleaf_t *leaf; + int sides; + + if (node->contents == CONTENTS_SOLID) + { + return; + } + +// add an efrag if the node is a leaf + + if ( node->contents < 0) + { + if (!r_pefragtopnode) + r_pefragtopnode = node; + + leaf = (mleaf_t *)node; + +// grab an efrag off the free list + ef = cl.free_efrags; + if (!ef) + { + Con_Printf ("Too many efrags!\n"); + return; // no free fragments... + } + cl.free_efrags = cl.free_efrags->entnext; + + ef->entity = r_addent; + +// add the entity link + *lastlink = ef; + lastlink = &ef->entnext; + ef->entnext = NULL; + +// set the leaf links + ef->leaf = leaf; + ef->leafnext = leaf->efrags; + leaf->efrags = ef; + + return; + } + +// NODE_MIXED + + splitplane = node->plane; + sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane); + + if (sides == 3) + { + // split on this plane + // if this is the first splitter of this bmodel, remember it + if (!r_pefragtopnode) + r_pefragtopnode = node; + } + +// recurse down the contacted sides + if (sides & 1) + R_SplitEntityOnNode (node->children[0]); + + if (sides & 2) + R_SplitEntityOnNode (node->children[1]); +} + +#ifdef USEFPM +void R_SplitEntityOnNodeFPM (mnode_FPM_t *node) +{ + efrag_FPM_t *ef; + mplane_FPM_t *splitplane; + mleaf_FPM_t *leaf; + int sides; + + if (node->contents == CONTENTS_SOLID) + { + return; + } + +// add an efrag if the node is a leaf + + if ( node->contents < 0) + { + if (!r_pefragtopnodeFPM) + r_pefragtopnodeFPM = node; + + leaf = (mleaf_FPM_t *)node; + +// grab an efrag off the free list + ef = clFPM.free_efrags; + if (!ef) + { + Con_Printf ("Too many efrags!\n"); + return; // no free fragments... + } + clFPM.free_efrags = clFPM.free_efrags->entnext; + + ef->entity = r_addentFPM; + +// add the entity link + *lastlinkFPM = ef; + lastlinkFPM = &ef->entnext; + ef->entnext = NULL; + +// set the leaf links + ef->leaf = leaf; + ef->leafnext = leaf->efrags; + leaf->efrags = ef; + + return; + } + +// NODE_MIXED + + splitplane = node->plane; + sides = BOX_ON_PLANE_SIDE_FPM(r_eminsFPM, r_emaxsFPM, splitplane); + + if (sides == 3) + { + // split on this plane + // if this is the first splitter of this bmodel, remember it + if (!r_pefragtopnodeFPM) + r_pefragtopnodeFPM = node; + } + +// recurse down the contacted sides + if (sides & 1) + R_SplitEntityOnNodeFPM (node->children[0]); + + if (sides & 2) + R_SplitEntityOnNodeFPM (node->children[1]); +} +#endif //USEFPM + +/* +=================== +R_SplitEntityOnNode2 +=================== +*/ +void R_SplitEntityOnNode2 (mnode_t *node) +{ + mplane_t *splitplane; + int sides; + + if (node->visframe != r_visframecount) + return; + + if (node->contents < 0) + { + if (node->contents != CONTENTS_SOLID) + r_pefragtopnode = node; // we've reached a non-solid leaf, so it's + // visible and not BSP clipped + return; + } + + splitplane = node->plane; + sides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane); + + if (sides == 3) + { + // remember first splitter + r_pefragtopnode = node; + return; + } + +// not split yet; recurse down the contacted side + if (sides & 1) + R_SplitEntityOnNode2 (node->children[0]); + else + R_SplitEntityOnNode2 (node->children[1]); +} + +#ifdef USEFPM +void R_SplitEntityOnNode2FPM (mnode_FPM_t *node) +{ + mplane_FPM_t *splitplane; + int sides; + + if (node->visframe != r_visframecount) + return; + + if (node->contents < 0) + { + if (node->contents != CONTENTS_SOLID) + r_pefragtopnodeFPM = node; // we've reached a non-solid leaf, so it's + // visible and not BSP clipped + return; + } + + splitplane = node->plane; + sides = BOX_ON_PLANE_SIDE_FPM(r_eminsFPM, r_emaxsFPM, splitplane); + + if (sides == 3) + { + // remember first splitter + r_pefragtopnodeFPM = node; + return; + } + +// not split yet; recurse down the contacted side + if (sides & 1) + R_SplitEntityOnNode2FPM (node->children[0]); + else + R_SplitEntityOnNode2FPM (node->children[1]); +} +#endif //USEFPM + +/* +=========== +R_AddEfrags +=========== +*/ +void R_AddEfrags (entity_t *ent) +{ + model_t *entmodel; + int i; + + if (!ent->model){ + return; + } + + if (ent == cl_entities){ + return; // never add the world + } + + r_addent = ent; + + lastlink = &ent->efrag; + r_pefragtopnode = NULL; + + entmodel = ent->model; + + for (i=0 ; i<3 ; i++) + { + r_emins[i] = ent->origin[i] + entmodel->mins[i]; + r_emaxs[i] = ent->origin[i] + entmodel->maxs[i]; + } + + R_SplitEntityOnNode (cl.worldmodel->nodes); + + ent->topnode = r_pefragtopnode; +} + +#ifdef USEFPM +void R_AddEfragsFPM (entity_FPM_t *ent) +{ + model_FPM_t *entmodel; + int i; + + if (!ent->model) + return; + + if (ent == cl_entitiesFPM) + return; // never add the world + + r_addentFPM = ent; + + lastlinkFPM = &ent->efrag; + r_pefragtopnodeFPM = NULL; + + entmodel = ent->model; + + for (i=0 ; i<3 ; i++) + { + r_eminsFPM[i] = ent->origin[i] + entmodel->mins[i]; + r_emaxsFPM[i] = ent->origin[i] + entmodel->maxs[i]; + } + + R_SplitEntityOnNodeFPM (clFPM.worldmodel->nodes); + + ent->topnode = r_pefragtopnodeFPM; +} +#endif //USEFPM + +/* +================ +R_StoreEfrags + +// FIXME: a lot of this goes away with edge-based +================ +*/ +void R_StoreEfrags (efrag_t **ppefrag) +{ + entity_t *pent; + model_t *clmodel; + efrag_t *pefrag; + + while ((pefrag = *ppefrag) != NULL) + { + pent = pefrag->entity; + clmodel = pent->model; + + switch (clmodel->type) + { + case mod_alias: + case mod_brush: + case mod_sprite: + pent = pefrag->entity; + + if ((pent->visframe != r_framecount) && + (cl_numvisedicts < MAX_VISEDICTS)) + { + cl_visedicts[cl_numvisedicts++] = pent; + + // mark that we've recorded this entity for this frame + pent->visframe = r_framecount; + } + + ppefrag = &pefrag->leafnext; + break; + + default: + Sys_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type); + } + } +} + +#ifdef USEFPM +void R_StoreEfragsFPM (efrag_FPM_t **ppefrag) +{ + entity_FPM_t *pent; + model_FPM_t *clmodel; + efrag_FPM_t *pefrag; + + + while ((pefrag = *ppefrag) != NULL) + { + pent = pefrag->entity; + clmodel = pent->model; + + switch (clmodel->type) + { + case mod_alias: + case mod_brush: + case mod_sprite: + pent = pefrag->entity; + + if ((pent->visframe != r_framecount) && + (cl_numvisedicts < MAX_VISEDICTS)) + { + cl_visedictsFPM[cl_numvisedicts++] = pent; + + // mark that we've recorded this entity for this frame + pent->visframe = r_framecount; + } + + ppefrag = &pefrag->leafnext; + break; + + default: + Sys_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type); + } + } +} +#endif //USEFPM diff --git a/project/jni/application/quake/source/r_light.c b/project/jni/application/quake/source/r_light.c new file mode 100644 index 000000000..3c18b2957 --- /dev/null +++ b/project/jni/application/quake/source/r_light.c @@ -0,0 +1,444 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_light.c + +#include "quakedef.h" +#include "r_local.h" + +int r_dlightframecount; + + +/* +================== +R_AnimateLight +================== +*/ +void R_AnimateLight (void) +{ + int i,j,k; + +// +// light animations +// 'm' is normal light, 'a' is no light, 'z' is double bright + i = (int)(cl.time*10); + for (j=0 ; jcontents < 0) + return; + + splitplane = node->plane; + dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; + + if (dist > light->radius) + { + R_MarkLights (light, bit, node->children[0]); + return; + } + if (dist < -light->radius) + { + R_MarkLights (light, bit, node->children[1]); + return; + } + +// mark the polygons + surf = cl.worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->dlightframe != r_dlightframecount) + { + surf->dlightbits = 0; + surf->dlightframe = r_dlightframecount; + } + surf->dlightbits |= bit; + } + + R_MarkLights (light, bit, node->children[0]); + R_MarkLights (light, bit, node->children[1]); +} + +#ifdef USEFPM +void R_MarkLightsFPM (dlight_FPM_t *light, int bit, mnode_FPM_t *node) +{ + mplane_FPM_t *splitplane; + fixedpoint_t dist; + msurface_FPM_t *surf; + int i; + + if (node->contents < 0) + return; + + splitplane = node->plane; + dist = FPM_SUB(DotProductFPM (light->origin, splitplane->normal), splitplane->dist); + + if (dist > light->radius) + { + R_MarkLightsFPM (light, bit, node->children[0]); + return; + } + if (dist < -light->radius) + { + R_MarkLightsFPM (light, bit, node->children[1]); + return; + } + +// mark the polygons + surf = clFPM.worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->dlightframe != r_dlightframecount) + { + surf->dlightbits = 0; + surf->dlightframe = r_dlightframecount; + } + surf->dlightbits |= bit; + } + + R_MarkLightsFPM (light, bit, node->children[0]); + R_MarkLightsFPM (light, bit, node->children[1]); +} +#endif //USEFPM + +/* +============= +R_PushDlights +============= +*/ +void R_PushDlights (void) +{ + int i; + dlight_t *l; + + r_dlightframecount = r_framecount + 1; // because the count hasn't + // advanced yet for this frame + l = cl_dlights; + + for (i=0 ; idie < cl.time || !l->radius) + continue; + + R_MarkLights ( l, 1<nodes ); + } + +} + +#ifdef USEFPM +void R_PushDlightsFPM (void) +{ + int i; + dlight_FPM_t *l; + + r_dlightframecount = r_framecount + 1; // because the count hasn't + // advanced yet for this frame + l = cl_dlightsFPM; + + for (i=0 ; idie < cl.time || !l->radius) + continue; + R_MarkLightsFPM ( l, 1<nodes ); + } +} +#endif //USEFPM + +/* +============================================================================= + +LIGHT SAMPLING + +============================================================================= +*/ + +int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) +{ + int r; + float front, back, frac; + int side; + mplane_t *plane; + vec3_t mid; + msurface_t *surf; + int s, t, ds, dt; + int i; + mtexinfo_t *tex; + byte *lightmap; + unsigned scale; + int maps; + + if (node->contents < 0) + return -1; // didn't hit anything + +// calculate mid point + +// FIXME: optimize for axial + plane = node->plane; + front = DotProduct (start, plane->normal) - plane->dist; + back = DotProduct (end, plane->normal) - plane->dist; + side = front < 0; + + if ( (back < 0) == side) + return RecursiveLightPoint (node->children[side], start, end); + + frac = front / (front-back); + mid[0] = start[0] + (end[0] - start[0])*frac; + mid[1] = start[1] + (end[1] - start[1])*frac; + mid[2] = start[2] + (end[2] - start[2])*frac; + +// go down front side + r = RecursiveLightPoint (node->children[side], start, mid); + if (r >= 0) + return r; // hit something + + if ( (back < 0) == side ) + return -1; // didn't hit anuthing + +// check for impact on this node + + surf = cl.worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->flags & SURF_DRAWTILED) + continue; // no lightmaps + + tex = surf->texinfo; + + s = (int)(DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3]); + t = (int)(DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3]); + + if (s < surf->texturemins[0] || + t < surf->texturemins[1]) + continue; + + ds = s - surf->texturemins[0]; + dt = t - surf->texturemins[1]; + + if ( ds > surf->extents[0] || dt > surf->extents[1] ) + continue; + + if (!surf->samples) + return 0; + + ds >>= 4; + dt >>= 4; + + lightmap = surf->samples; + r = 0; + if (lightmap) + { + + lightmap += dt * ((surf->extents[0]>>4)+1) + ds; + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + r += *lightmap * scale; + lightmap += ((surf->extents[0]>>4)+1) * + ((surf->extents[1]>>4)+1); + } + + r >>= 8; + } + + return r; + } + +// go down back side + return RecursiveLightPoint (node->children[!side], mid, end); +} + +#ifdef USEFPM +int RecursiveLightPointFPM (mnode_FPM_t *node, vec3_FPM_t start, vec3_FPM_t end) +{ + int r; + fixedpoint_t front, back, frac; + int side; + mplane_FPM_t *plane; + vec3_FPM_t mid; + msurface_FPM_t *surf; + int s, t, ds, dt; + int i; + mtexinfo_FPM_t *tex; + byte *lightmap; + unsigned scale; + int maps; + + if (node->contents < 0) + return -1; // didn't hit anything + +// calculate mid point + +// FIXME: optimize for axial + plane = node->plane; + front = FPM_SUB(DotProductFPM (start, plane->normal), plane->dist); + back = FPM_SUB(DotProductFPM (end, plane->normal), plane->dist); + side = front < 0; + + if ( (back < 0) == side) + return RecursiveLightPointFPM (node->children[side], start, end); + + frac = FPM_DIV(front, FPM_SUB(front,back)); + mid[0] = FPM_ADD(start[0], FPM_MUL(FPM_SUB(end[0], start[0]),frac)); + mid[1] = FPM_ADD(start[1], FPM_MUL(FPM_SUB(end[1], start[1]),frac)); + mid[2] = FPM_ADD(start[2], FPM_MUL(FPM_SUB(end[2], start[2]),frac)); + +// go down front side + r = RecursiveLightPointFPM (node->children[side], start, mid); + if (r >= 0) + return r; // hit something + + if ( (back < 0) == side ) + return -1; // didn't hit anuthing + +// check for impact on this node + + surf = clFPM.worldmodel->surfaces + node->firstsurface; + for (i=0 ; inumsurfaces ; i++, surf++) + { + if (surf->flags & SURF_DRAWTILED) + continue; // no lightmaps + + tex = surf->texinfo; + + s = FPM_TOLONG(FPM_ADD(DotProductFPM (mid, tex->vecs[0]), tex->vecs[0][3])); + t = FPM_TOLONG(FPM_ADD(DotProductFPM (mid, tex->vecs[1]), tex->vecs[1][3])); + + if (s < surf->texturemins[0] || + t < surf->texturemins[1]) + continue; + + ds = s - surf->texturemins[0]; + dt = t - surf->texturemins[1]; + + if ( ds > surf->extents[0] || dt > surf->extents[1] ) + continue; + + if (!surf->samples) + return 0; + + ds >>= 4; + dt >>= 4; + + lightmap = surf->samples; + r = 0; + if (lightmap) + { + + lightmap += dt * ((surf->extents[0]>>4)+1) + ds; + + for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; + maps++) + { + scale = d_lightstylevalue[surf->styles[maps]]; + r += *lightmap * scale; + lightmap += ((surf->extents[0]>>4)+1) * + ((surf->extents[1]>>4)+1); + } + + r >>= 8; + } + + return r; + } + +// go down back side + return RecursiveLightPointFPM (node->children[!side], mid, end); +} +#endif //USEFPM + +int R_LightPoint (vec3_t p) +{ + vec3_t end; + int r; + + if (!cl.worldmodel->lightdata) + return 255; + + end[0] = p[0]; + end[1] = p[1]; + end[2] = p[2] - 2048; + + r = RecursiveLightPoint (cl.worldmodel->nodes, p, end); + + if (r == -1) + r = 0; + + if (r < r_refdef.ambientlight) + r = r_refdef.ambientlight; + + return r; +} + +#ifdef USEFPM +int R_LightPointFPM (vec3_FPM_t p) +{ + vec3_FPM_t end; + int r; + + if (!clFPM.worldmodel->lightdata) + return 255; + + end[0] = p[0]; + end[1] = p[1]; + end[2] = FPM_SUB(p[2], FPM_FROMLONG(2048)); + + r = RecursiveLightPointFPM (clFPM.worldmodel->nodes, p, end); + + if (r == -1) + r = 0; + + if (r < r_refdefFPM.ambientlight) + r = r_refdefFPM.ambientlight; + + return r; +} +#endif //USEFPM diff --git a/project/jni/application/quake/source/r_local.h b/project/jni/application/quake/source/r_local.h new file mode 100644 index 000000000..9dd3caa17 --- /dev/null +++ b/project/jni/application/quake/source/r_local.h @@ -0,0 +1,428 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_local.h -- private refresh defs + +#ifndef GLQUAKE +#include "r_shared.h" + +#define ALIAS_BASE_SIZE_RATIO (1.0 / 11.0) + // normalizing factor so player model works out to about + // 1 pixel per triangle + +#define BMODEL_FULLY_CLIPPED 0x10 // value returned by R_BmodelCheckBBox () + // if bbox is trivially rejected + +// TODO: put in span spilling to shrink list size +// !!! if this is changed, it must be changed in d_polysa.s too !!! +#define DPS_MAXSPANS MAXHEIGHT+1 + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct { + void *pdest; + short *pz; + int count; + byte *ptex; + int sfrac, tfrac, light, zi; +} spanpackage_t; + +//=========================================================================== +// viewmodel lighting + +typedef struct { + int ambientlight; + int shadelight; + float *plightvec; +} alight_t; +/* +typedef struct { + int ambientlight; + int shadelight; + fixedpoint_t *plightvec; +} alight_FPM_t; +*/ +//=========================================================================== +// clipped bmodel edges + +typedef struct bedge_s +{ + mvertex_t *v[2]; + struct bedge_s *pnext; +} bedge_t; +/* +typedef struct bedge_FPM_s +{ + mvertex_FPM_t *v[2]; + struct bedge_FPM_s *pnext; +} bedge_FPM_t; +*/ +typedef struct { + float fv[3]; // viewspace x, y +} auxvert_t; +/* +typedef struct { + fixedpoint_t fv[3]; // viewspace x, y +} auxvert_FPM_t; +*/ +//=========================================================================== + +extern cvar_t r_draworder; +extern cvar_t r_speeds; +extern cvar_t r_timegraph; +extern cvar_t r_graphheight; +extern cvar_t r_clearcolor; +extern cvar_t r_waterwarp; +extern cvar_t r_fullbright; +extern cvar_t r_drawentities; +extern cvar_t r_aliasstats; +extern cvar_t r_dspeeds; +extern cvar_t r_drawflat; +extern cvar_t r_ambient; +extern cvar_t r_reportsurfout; +extern cvar_t r_maxsurfs; +extern cvar_t r_numsurfs; +extern cvar_t r_reportedgeout; +extern cvar_t r_maxedges; +extern cvar_t r_numedges; +//Dan East: +extern cvar_t r_maxparticles; + +#define XCENTERING (1.0 / 2.0) +#define YCENTERING (1.0 / 2.0) + +//#define XCENTERINGFPM FPM_FROMFLOAT(1.0 / 2.0) +//#define YCENTERINGFPM FPM_FROMFLOAT(1.0 / 2.0) + +#define CLIP_EPSILON 0.001 + +#define BACKFACE_EPSILON 0.01 + +//=========================================================================== + +#define DIST_NOT_SET 98765 + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct clipplane_s +{ + vec3_t normal; + float dist; + struct clipplane_s *next; + byte leftedge; + byte rightedge; + byte reserved[2]; +} clipplane_t; + +typedef struct clipplane_fxp_s +{ + int normal[3]; + int dist; + struct clipplane_fxp_s *next; + byte leftedge; + byte rightedge; + byte reserved[2]; +} clipplane_fxp_t; +/* +typedef struct clipplane_FPM_s +{ + vec3_FPM_t normal; + fixedpoint_t dist; + struct clipplane_FPM_s *next; + byte leftedge; + byte rightedge; + byte reserved[2]; +} clipplane_FPM_t; +*/ +extern clipplane_t view_clipplanes[4]; +//extern clipplane_FPM_t view_clipplanesFPM[4]; + +#ifdef USE_PQ_OPT2 +extern clipplane_fxp_t view_clipplanes_fxp[4]; +#endif + +//============================================================================= + +void R_RenderWorld (void); +//void R_RenderWorldFPM (void); + +//============================================================================= + +extern mplane_t screenedge[4]; +//extern mplane_FPM_t screenedgeFPM[4]; + +extern vec3_t r_origin; + +extern vec3_t r_entorigin; +//extern vec3_FPM_t r_entoriginFPM; + +extern float screenAspect; +extern float verticalFieldOfView; +extern float xOrigin, yOrigin; + +extern int r_visframecount; + +//============================================================================= + +extern int vstartscan; + + +void R_ClearPolyList (void); +void R_DrawPolyList (void); + +// +// current entity info +// +extern qboolean insubmodel; +extern vec3_t r_worldmodelorg; +//extern vec3_FPM_t r_worldmodelorgFPM; + +void R_DrawSprite (void); +//void R_DrawSpriteFPM (void); +void R_RenderFace (msurface_t *fa, int clipflags); +//void R_RenderFaceFPM (msurface_FPM_t *fa, int clipflags); +void R_RenderPoly (msurface_t *fa, int clipflags); +//void R_RenderPolyFPM (msurface_FPM_t *fa, int clipflags); +void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf); +//void R_RenderBmodelFaceFPM (bedge_FPM_t *pedges, msurface_FPM_t *psurf); +void R_TransformPlane (mplane_t *p, float *normal, float *dist); +void R_TransformFrustum (void); +//void R_TransformFrustumFPM (void); +void R_SetSkyFrame (void); +//void R_SetSkyFrameFPM (void); +void R_DrawSurfaceBlock16 (void); +void R_DrawSurfaceBlock8 (void); +texture_t *R_TextureAnimation (texture_t *base); +//texture_t *R_TextureAnimationFPM (texture_t *base); + +#if id386 + +void R_DrawSurfaceBlock8_mip0 (void); +void R_DrawSurfaceBlock8_mip1 (void); +void R_DrawSurfaceBlock8_mip2 (void); +void R_DrawSurfaceBlock8_mip3 (void); + +#endif + +void R_GenSkyTile (void *pdest); +void R_GenSkyTile16 (void *pdest); +void R_Surf8Patch (void); +void R_Surf16Patch (void); +void R_DrawSubmodelPolygons (model_t *pmodel, int clipflags); +//void R_DrawSubmodelPolygonsFPM (model_FPM_t *pmodel, int clipflags); +void R_DrawSolidClippedSubmodelPolygons (model_t *pmodel); +//void R_DrawSolidClippedSubmodelPolygonsFPM (model_FPM_t *pmodel); + +void R_AddPolygonEdges (emitpoint_t *pverts, int numverts, int miplevel); +surf_t *R_GetSurf (void); +void R_AliasDrawModel (alight_t *plighting); +//void R_AliasDrawModelFPM (alight_FPM_t *plighting); +void R_BeginEdgeFrame (void); +//void R_BeginEdgeFrameFPM (void); +void R_ScanEdges (void); +//void R_ScanEdgesFPM (void); +void D_DrawSurfaces (void); +//void D_DrawSurfacesFPM (void); +void R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist); +void R_StepActiveU (edge_t *pedge); +void R_RemoveEdges (edge_t *pedge); + +extern void R_Surf8Start (void); +extern void R_Surf8End (void); +extern void R_Surf16Start (void); +extern void R_Surf16End (void); +extern void R_EdgeCodeStart (void); +extern void R_EdgeCodeEnd (void); + +extern void R_RotateBmodel (void); +//extern void R_RotateBmodelFPM (void); + +extern int c_faceclip; +extern int r_polycount; +extern int r_wholepolycount; + +extern model_t *cl_worldmodel; + +extern int *pfrustum_indexes[4]; + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +#define NEAR_CLIP 0.01 +//#define NEAR_CLIP_FPM FPM_FROMFLOAT(0.01) + +extern int ubasestep, errorterm, erroradjustup, erroradjustdown; +extern int vstartscan; + +extern fixed16_t sadjust, tadjust; +extern fixed16_t bbextents, bbextentt; + +#define MAXBVERTINDEXES 1000 // new clipped vertices when clipping bmodels + // to the world BSP +extern mvertex_t *r_ptverts, *r_ptvertsmax; + +extern vec3_t sbaseaxis[3], tbaseaxis[3]; +extern float entity_rotation[3][3]; + +extern int reinit_surfcache; + +extern int r_currentkey; +extern int r_currentbkey; + +typedef struct btofpoly_s { + int clipflags; + msurface_t *psurf; +} btofpoly_t; +/* +typedef struct btofpoly_FPM_s { + int clipflags; + msurface_FPM_t *psurf; +} btofpoly_FPM_t; +*/ +#define MAX_BTOFPOLYS 5000 // FIXME: tune this + +extern int numbtofpolys; +extern btofpoly_t *pbtofpolys; +//extern btofpoly_FPM_t *pbtofpolysFPM; + +void R_InitTurb (void); +void R_ZDrawSubmodelPolys (model_t *clmodel); +//void R_ZDrawSubmodelPolysFPM (model_FPM_t *clmodel); + +//========================================================= +// Alias models +//========================================================= + +#define MAXALIASVERTS 2000 // TODO: tune this +#define ALIAS_Z_CLIP_PLANE 5 +//#define ALIAS_Z_CLIP_PLANE_FPM FPM_FROMLONG(5) + +extern int numverts; +extern int a_skinwidth; +extern mtriangle_t *ptriangles; +extern int numtriangles; +extern aliashdr_t *paliashdr; +extern mdl_t *pmdl; +extern float leftclip, topclip, rightclip, bottomclip; +extern int r_acliptype; +extern finalvert_t *pfinalverts; +extern auxvert_t *pauxverts; +//extern auxvert_FPM_t *pauxvertsFPM; + +qboolean R_AliasCheckBBox (void); +//qboolean R_AliasCheckBBoxFPM (void); + +//========================================================= +// turbulence stuff + +#define AMP 8*0x10000 +#define AMP2 3 +#define SPEED 20 + +//========================================================= +// particle stuff + +void R_DrawParticles (void); +//void R_DrawParticlesFPM (void); +void R_InitParticles (void); +//void R_InitParticlesFPM (void); +void R_ClearParticles (void); +//void R_ClearParticlesFPM (void); +void R_ReadPointFile_f (void); +void R_SurfacePatch (void); +//void R_SurfacePatchFPM (void); + +extern int r_amodels_drawn; +extern edge_t *auxedges; +//extern edge_FPM_t *auxedgesFPM; +extern int r_numallocatededges; +extern edge_t *r_edges, *edge_p, *edge_max; +//extern edge_FPM_t *r_edgesFPM, *edge_FPM_p, *edge_maxFPM; + +extern edge_t *newedges[MAXHEIGHT]; +extern edge_t *removeedges[MAXHEIGHT]; +//extern edge_FPM_t *newedgesFPM[MAXHEIGHT]; +//extern edge_FPM_t *removeedgesFPM[MAXHEIGHT]; + +extern int screenwidth; + +// FIXME: make stack vars when debugging done +extern edge_t edge_head; +extern edge_t edge_tail; +extern edge_t edge_aftertail; +extern int r_bmodelactive; +extern vrect_t *pconupdate; + +extern float aliasxscale, aliasyscale, aliasxcenter, aliasycenter; +//extern fixedpoint_t aliasxscaleFPM, aliasyscaleFPM, aliasxcenterFPM, aliasycenterFPM; +extern float r_aliastransition, r_resfudge; +//extern fixedpoint_t r_aliastransitionFPM, r_resfudgeFPM; + +extern int r_outofsurfaces; +extern int r_outofedges; + +extern mvertex_t *r_pcurrentvertbase; +//extern mvertex_FPM_t *r_pcurrentvertbaseFPM; +#ifdef USE_PQ_OPT2 +extern mvertex_fxp_t *r_pcurrentvertbase_fxp; +#endif +extern int r_maxvalidedgeoffset; + +void R_AliasClipTriangle (mtriangle_t *ptri); +//void R_AliasClipTriangleFPM (mtriangle_t *ptri); + +extern float r_time1; +extern float dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2; +extern float se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2; +extern int r_frustum_indexes[4*6]; +extern int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs; +extern qboolean r_surfsonstack; +extern cshift_t cshift_water; +extern qboolean r_dowarpold, r_viewchanged; + +extern mleaf_t *r_viewleaf, *r_oldviewleaf; +//extern mleaf_FPM_t *r_viewleafFPM, *r_oldviewleafFPM; + +extern vec3_t r_emins, r_emaxs; +//extern vec3_FPM_t r_eminsFPM, r_emaxsFPM; +extern mnode_t *r_pefragtopnode; +//extern mnode_FPM_t *r_pefragtopnodeFPM; +extern int r_clipflags; +extern int r_dlightframecount; +extern qboolean r_fov_greater_than_90; + +void R_StoreEfrags (efrag_t **ppefrag); +//void R_StoreEfragsFPM (efrag_FPM_t **ppefrag); +void R_TimeRefresh_f (void); +void R_TimeGraph (void); +//void R_TimeGraphFPM (void); +void R_PrintAliasStats (void); +void R_PrintTimes (void); +void R_PrintDSpeeds (void); +void R_AnimateLight (void); +int R_LightPoint (vec3_t p); +//int R_LightPointFPM (vec3_FPM_t p); +void R_SetupFrame (void); +//void R_SetupFrameFPM (void); +void R_cshift_f (void); +void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1); +//void R_EmitEdgeFPM (mvertex_FPM_t *pv0, mvertex_FPM_t *pv1); +void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip); +void R_SplitEntityOnNode2 (mnode_t *node); +//void R_SplitEntityOnNode2FPM (mnode_FPM_t *node); +void R_MarkLights (dlight_t *light, int bit, mnode_t *node); +//void R_MarkLightsFPM (dlight_FPM_t *light, int bit, mnode_FPM_t *node); + +#endif diff --git a/project/jni/application/quake/source/r_main.c b/project/jni/application/quake/source/r_main.c new file mode 100644 index 000000000..5f9be9bb7 --- /dev/null +++ b/project/jni/application/quake/source/r_main.c @@ -0,0 +1,2028 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_main.c + +#include "quakedef.h" +#include "r_local.h" + +//#define PASSAGES + +void *colormap; +vec3_t viewlightvec; +alight_t r_viewlighting = {128, 192, viewlightvec}; + +float r_time1; +int r_numallocatededges; +qboolean r_drawpolys; +qboolean r_drawculledpolys; +qboolean r_worldpolysbacktofront; +qboolean r_recursiveaffinetriangles = true; +int r_pixbytes = 1; +float r_aliasuvscale = 1.0; +int r_outofsurfaces; +int r_outofedges; + +qboolean r_dowarp, r_dowarpold, r_viewchanged; + +int numbtofpolys; +btofpoly_t *pbtofpolys; +mvertex_t *r_pcurrentvertbase; +#ifdef USE_PQ_OPT2 +mvertex_fxp_t *r_pcurrentvertbase_fxp; +#endif + +int c_surf; +int r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs; +qboolean r_surfsonstack; +int r_clipflags; + +byte *r_warpbuffer; + +byte *r_stack_start; + +qboolean r_fov_greater_than_90; + +// +// view origin +// +vec3_t vup, base_vup; +vec3_t vpn, base_vpn; +vec3_t vright, base_vright; +vec3_t r_origin; + +#ifdef USE_PQ_OPT1 +int vup_fxp[3]; +int vpn_fxp[3]; +int vright_fxp[3]; +int xscale_fxp, yscale_fxp; +int xcenter_fxp, ycenter_fxp; +int r_refdef_fvrectx_adj_fxp; +int r_refdef_fvrectright_adj_fxp; +int r_refdef_fvrecty_adj_fxp; +int r_refdef_fvrectbottom_adj_fxp; +extern int modelorg_fxp[3]; +#endif +// +// screen size info +// +refdef_t r_refdef; +float xcenter, ycenter; +float xscale, yscale; +float xscaleinv, yscaleinv; +float xscaleshrink, yscaleshrink; +float aliasxscale, aliasyscale, aliasxcenter, aliasycenter; +fixedpoint_t aliasxscaleFPM, aliasyscaleFPM, aliasxcenterFPM, aliasycenterFPM; +int screenwidth; +#ifdef USE_PQ_OPT3 +int xscaleinv_fxp, yscaleinv_fxp; +int xcenter_fxp, ycenter_fxp; +#endif + +float pixelAspect; +float screenAspect; +float verticalFieldOfView; +float xOrigin, yOrigin; + +mplane_t screenedge[4]; + +// +// refresh flags +// +int r_framecount = 1; // so frame counts initialized to 0 don't match +int r_visframecount; +int d_spanpixcount; +int r_polycount; +int r_drawnpolycount; +int r_wholepolycount; + +#define VIEWMODNAME_LENGTH 256 +char viewmodname[VIEWMODNAME_LENGTH+1]; +int modcount; + +int *pfrustum_indexes[4]; +int r_frustum_indexes[4*6]; + +int reinit_surfcache = 1; // if 1, surface cache is currently empty and + // must be reinitialized for current cache size + +mleaf_t *r_viewleaf, *r_oldviewleaf; + +texture_t *r_notexture_mip; + +float r_aliastransition, r_resfudge; + + +#ifdef USEFPM +mleaf_FPM_t *r_viewleafFPM, *r_oldviewleafFPM; +mplane_FPM_t screenedgeFPM[4]; +fixedpoint_t pixelAspectFPM; +fixedpoint_t screenAspectFPM; +fixedpoint_t verticalFieldOfViewFPM; +fixedpoint_t xOriginFPM, yOriginFPM; +fixedpoint_t aliasxscaleFPM, aliasyscaleFPM, aliasxcenterFPM, aliasycenterFPM; +fixedpoint_t r_aliastransitionFPM, r_resfudgeFPM; +fixedpoint_t aliasxscaleFPM, aliasyscaleFPM, aliasxcenterFPM, aliasycenterFPM; +fixedpoint_t xscaleshrinkFPM, yscaleshrinkFPM; +fixedpoint_t xscaleinvFPM, yscaleinvFPM; +fixedpoint_t xscaleFPM, yscaleFPM; +fixedpoint_t xcenterFPM, ycenterFPM; +refdef_FPM_t r_refdefFPM; +vec3_FPM_t vupFPM, base_vupFPM; +vec3_FPM_t vpnFPM, base_vpnFPM; +vec3_FPM_t vrightFPM, base_vrightFPM; +vec3_FPM_t r_originFPM; +mvertex_FPM_t *r_pcurrentvertbaseFPM; +btofpoly_FPM_t *pbtofpolysFPM; +fixedpoint_t r_aliasuvscaleFPM = FPM_FROMFLOATC(1.0); +vec3_FPM_t viewlightvecFPM; +alight_FPM_t r_viewlightingFPM = {FPM_FROMLONGC(128), FPM_FROMLONGC(192), viewlightvecFPM}; +#endif //USEFPM + +int d_lightstylevalue[256]; // 8.8 fraction of base light value + +float dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2; +float se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2; + +void R_MarkLeaves (void); + +cvar_t r_draworder = {"r_draworder","0"}; +cvar_t r_speeds = {"r_speeds","0"}; +cvar_t r_timegraph = {"r_timegraph","0"}; +cvar_t r_graphheight = {"r_graphheight","10"}; +cvar_t r_clearcolor = {"r_clearcolor","2"}; +cvar_t r_skycolor = {"r_skycolor", "4"}; +cvar_t r_fastsky = {"r_fastsky", "0"}; +cvar_t r_waterwarp = {"r_waterwarp", "0"}; +cvar_t r_fullbright = {"r_fullbright","0"}; +cvar_t r_drawentities = {"r_drawentities","1"}; +cvar_t r_drawviewmodel = {"r_drawviewmodel","1"}; +cvar_t r_aliasstats = {"r_polymodelstats","0"}; +cvar_t r_dspeeds = {"r_dspeeds","0"}; +cvar_t r_drawflat = {"r_drawflat", "0"}; +cvar_t r_ambient = {"r_ambient", "0"}; +cvar_t r_reportsurfout = {"r_reportsurfout", "0"}; +cvar_t r_maxsurfs = {"r_maxsurfs", "0"}; +cvar_t r_numsurfs = {"r_numsurfs", "0"}; +cvar_t r_reportedgeout = {"r_reportedgeout", "0"}; +cvar_t r_maxedges = {"r_maxedges", "0"}; +cvar_t r_numedges = {"r_numedges", "0"}; +cvar_t r_aliastransbase = {"r_aliastransbase", "200"}; +cvar_t r_aliastransadj = {"r_aliastransadj", "100"}; +cvar_t r_fastturb = {"r_fastturb", "0"}; + +//Dan East: Added: +cvar_t r_maxparticles = {"r_maxparticles","512"}; + +extern cvar_t scr_fov; + +void CreatePassages (void); +void SetVisibilityByPassages (void); + +/* +================== +R_InitTextures +================== +*/ +void R_InitTextures (void) +{ + int x,y, m; + byte *dest; + +// create a simple checkerboard texture for the default + r_notexture_mip = Hunk_AllocName (sizeof(texture_t) + 16*16+8*8+4*4+2*2, "notexture"); + + r_notexture_mip->width = r_notexture_mip->height = 16; + r_notexture_mip->offsets[0] = sizeof(texture_t); + r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16; + r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8; + r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4; + + for (m=0 ; m<4 ; m++) + { + dest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m]; + for (y=0 ; y< (16>>m) ; y++) + for (x=0 ; x< (16>>m) ; x++) + { + if ( (y< (8>>m) ) ^ (x< (8>>m) ) ) + *dest++ = 0; + else + *dest++ = 0xff; + } + } +} + +/* +=============== +R_Init +=============== +*/ +void R_Init (void) +{ + int dummy; + +// get stack position so we can guess if we are going to overflow + r_stack_start = (byte *)&dummy; + + R_InitTurb (); + + Cmd_AddCommand ("timerefresh", R_TimeRefresh_f); + Cmd_AddCommand ("pointfile", R_ReadPointFile_f); + + Cvar_RegisterVariable (&r_draworder); + Cvar_RegisterVariable (&r_speeds); + Cvar_RegisterVariable (&r_timegraph); + Cvar_RegisterVariable (&r_graphheight); + Cvar_RegisterVariable (&r_drawflat); + Cvar_RegisterVariable (&r_ambient); + Cvar_RegisterVariable (&r_clearcolor); + Cvar_RegisterVariable (&r_waterwarp); + Cvar_RegisterVariable (&r_skycolor); + Cvar_RegisterVariable (&r_fastsky); + Cvar_RegisterVariable (&r_fastturb); + Cvar_RegisterVariable (&r_fullbright); + Cvar_RegisterVariable (&r_drawentities); + Cvar_RegisterVariable (&r_drawviewmodel); + Cvar_RegisterVariable (&r_aliasstats); + Cvar_RegisterVariable (&r_dspeeds); + Cvar_RegisterVariable (&r_reportsurfout); + Cvar_RegisterVariable (&r_maxsurfs); + Cvar_RegisterVariable (&r_numsurfs); + Cvar_RegisterVariable (&r_reportedgeout); + Cvar_RegisterVariable (&r_maxedges); + Cvar_RegisterVariable (&r_numedges); + Cvar_RegisterVariable (&r_aliastransbase); + Cvar_RegisterVariable (&r_aliastransadj); + //Dan East: + Cvar_RegisterVariable (&r_maxparticles); + + Cvar_SetValue ("r_maxedges", (float)NUMSTACKEDGES); + Cvar_SetValue ("r_maxsurfs", (float)NUMSTACKSURFACES); + + view_clipplanes[0].leftedge = true; + view_clipplanes[1].rightedge = true; + view_clipplanes[1].leftedge = view_clipplanes[2].leftedge = + view_clipplanes[3].leftedge = false; + view_clipplanes[0].rightedge = view_clipplanes[2].rightedge = + view_clipplanes[3].rightedge = false; + + r_refdef.xOrigin = XCENTERING; + r_refdef.yOrigin = YCENTERING; + + R_InitParticles (); + +// TODO: collect 386-specific code in one place +#if id386 + Sys_MakeCodeWriteable ((long)R_EdgeCodeStart, + (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart); +#endif // id386 + + D_Init (); +} + +#ifdef USEFPM +void R_InitFPM (void) +{ + int dummy; + +// get stack position so we can guess if we are going to overflow + r_stack_start = (byte *)&dummy; + + R_InitTurb (); + +//#ifndef USEFLOAT + Cmd_AddCommand ("timerefresh", R_TimeRefresh_f); + Cmd_AddCommand ("pointfile", R_ReadPointFile_f); + + Cvar_RegisterVariable (&r_draworder); + Cvar_RegisterVariable (&r_speeds); + Cvar_RegisterVariable (&r_timegraph); + Cvar_RegisterVariable (&r_graphheight); + Cvar_RegisterVariable (&r_drawflat); + Cvar_RegisterVariable (&r_ambient); + Cvar_RegisterVariable (&r_clearcolor); + Cvar_RegisterVariable (&r_waterwarp); + Cvar_RegisterVariable (&r_skycolor); + Cvar_RegisterVariable (&r_fastsky); + Cvar_RegisterVariable (&r_fastturb); + Cvar_RegisterVariable (&r_fullbright); + Cvar_RegisterVariable (&r_drawentities); + Cvar_RegisterVariable (&r_drawviewmodel); + Cvar_RegisterVariable (&r_aliasstats); + Cvar_RegisterVariable (&r_dspeeds); + Cvar_RegisterVariable (&r_reportsurfout); + Cvar_RegisterVariable (&r_maxsurfs); + Cvar_RegisterVariable (&r_numsurfs); + Cvar_RegisterVariable (&r_reportedgeout); + Cvar_RegisterVariable (&r_maxedges); + Cvar_RegisterVariable (&r_numedges); + Cvar_RegisterVariable (&r_aliastransbase); + Cvar_RegisterVariable (&r_aliastransadj); + + Cvar_SetValue ("r_maxedges", (float)NUMSTACKEDGES); + Cvar_SetValue ("r_maxsurfs", (float)NUMSTACKSURFACES); +//#endif + + view_clipplanesFPM[0].leftedge = true; + view_clipplanesFPM[1].rightedge = true; + view_clipplanesFPM[1].leftedge = view_clipplanesFPM[2].leftedge = + view_clipplanesFPM[3].leftedge = false; + view_clipplanesFPM[0].rightedge = view_clipplanesFPM[2].rightedge = + view_clipplanesFPM[3].rightedge = false; + + r_refdefFPM.xOrigin = XCENTERINGFPM; + r_refdefFPM.yOrigin = YCENTERINGFPM; + + R_InitParticlesFPM (); + +// TODO: collect 386-specific code in one place +//Dan: id386 not defined for our builds +#if id386 + Sys_MakeCodeWriteable ((long)R_EdgeCodeStart, + (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart); +#endif // id386 + + D_InitFPM (); +} +#endif //USEFPM + +/* +=============== +R_NewMap +=============== +*/ +void R_NewMap (void) +{ + int i; + +// clear out efrags in case the level hasn't been reloaded +// FIXME: is this one short? + for (i=0 ; inumleafs ; i++) + cl.worldmodel->leafs[i].efrags = NULL; + + r_viewleaf = NULL; + R_ClearParticles (); + + r_cnumsurfs = (int)r_maxsurfs.value; + + if (r_cnumsurfs <= MINSURFACES) + r_cnumsurfs = MINSURFACES; + +// //Dan: testing: +// r_cnumsurfs=100; + if (r_cnumsurfs > NUMSTACKSURFACES) + { + surfaces = Hunk_AllocName (r_cnumsurfs * sizeof(surf_t), "surfaces"); + surface_p = surfaces; + surf_max = &surfaces[r_cnumsurfs]; + r_surfsonstack = false; + // surface 0 doesn't really exist; it's just a dummy because index 0 + // is used to indicate no edge attached to surface + surfaces--; + R_SurfacePatch (); + } + else + { + r_surfsonstack = true; + } + + r_maxedgesseen = 0; + r_maxsurfsseen = 0; + + r_numallocatededges = (int)r_maxedges.value; + + if (r_numallocatededges < MINEDGES) + r_numallocatededges = MINEDGES; + +// //Dan: testing: +// r_numallocatededges=600; + + if (r_numallocatededges <= NUMSTACKEDGES) + { + auxedges = NULL; + } + else + { + auxedges = Hunk_AllocName (r_numallocatededges * sizeof(edge_t), + "edges"); + } + + r_dowarpold = false; + r_viewchanged = false; +#ifdef PASSAGES +CreatePassages (); +#endif +} + +#ifdef USEFPM +void R_NewMapFPM (void) +{ + int i; + +// clear out efrags in case the level hasn't been reloaded +// FIXME: is this one short? + for (i=0 ; inumleafs ; i++) + clFPM.worldmodel->leafs[i].efrags = NULL; + + r_viewleafFPM = NULL; + R_ClearParticlesFPM (); + + r_cnumsurfs = (int)r_maxsurfs.value; + + if (r_cnumsurfs <= MINSURFACES) + r_cnumsurfs = MINSURFACES; + + if (r_cnumsurfs > NUMSTACKSURFACES) + { + surfacesFPM = Hunk_AllocName (r_cnumsurfs * sizeof(surf_FPM_t), "surfaces"); + surface_FPM_p = surfacesFPM; + surf_maxFPM = &surfacesFPM[r_cnumsurfs]; + r_surfsonstack = false; + // surface 0 doesn't really exist; it's just a dummy because index 0 + // is used to indicate no edge attached to surface + surfacesFPM--; + R_SurfacePatchFPM (); + } + else + { + r_surfsonstack = true; + } + + r_maxedgesseen = 0; + r_maxsurfsseen = 0; + + r_numallocatededges = (int)r_maxedges.value; + + if (r_numallocatededges < MINEDGES) + r_numallocatededges = MINEDGES; + + if (r_numallocatededges <= NUMSTACKEDGES) + { + auxedgesFPM = NULL; + } + else + { + auxedgesFPM = Hunk_AllocName (r_numallocatededges * sizeof(edge_FPM_t), + "edges"); + } + + r_dowarpold = false; + r_viewchanged = false; +//Dan: not defined for our builds +#ifdef PASSAGES +CreatePassages (); +#endif +} +#endif //USEFPM + +/* +=============== +R_SetVrect +=============== +*/ +void R_SetVrect (vrect_t *pvrectin, vrect_t *pvrect, int lineadj) +{ + int h; + float size; + + size = scr_viewsize.value > 100 ? 100 : scr_viewsize.value; + if (cl.intermission) + { + size = 100; + lineadj = 0; + } + size /= 100; + + h = pvrectin->height - lineadj; + pvrect->width = (int)(pvrectin->width * size); + if (pvrect->width < 96) + { + size = (float)(96.0 / pvrectin->width); + pvrect->width = 96; // min for icons + } + pvrect->width &= ~7; + pvrect->height = (int)(pvrectin->height * size); + if (pvrect->height > pvrectin->height - lineadj) + pvrect->height = pvrectin->height - lineadj; + + pvrect->height &= ~1; + + pvrect->x = (pvrectin->width - pvrect->width)/2; + pvrect->y = (h - pvrect->height)/2; + + { + if (lcd_x.value) + { + pvrect->y >>= 1; + pvrect->height >>= 1; + } + } +} + +#ifdef USEFPM +void R_SetVrectFPM (vrect_t *pvrectin, vrect_t *pvrect, int lineadj) +{ + int h; + fixedpoint_t size; + fixedpoint_t tmp; + + tmp=FPM_FROMFLOAT(scr_viewsize.value); + size = tmp > FPM_FROMLONGC(100) ? FPM_FROMLONGC(100) : tmp; + if (clFPM.intermission) + { + size = FPM_FROMLONGC(100); + lineadj = 0; + } + size = FPM_DIVINT(size, 100); + + h = pvrectin->height - lineadj; + pvrect->width = FPM_TOLONG(FPM_MUL(FPM_FROMLONG(pvrectin->width), size)); + if (pvrect->width < 96) + { + size = FPM_DIVINT(FPM_FROMFLOATC(96.0), pvrectin->width); + pvrect->width = 96; // min for icons + } + pvrect->width &= ~7; + pvrect->height = FPM_TOLONG(FPM_DIV(FPM_FROMLONG(pvrectin->height), size)); + if (pvrect->height > pvrectin->height - lineadj) + pvrect->height = pvrectin->height - lineadj; + + pvrect->height &= ~1; + + pvrect->x = (pvrectin->width - pvrect->width)/2; + pvrect->y = (h - pvrect->height)/2; + + { + if (lcd_x.value) + { + pvrect->y >>= 1; + pvrect->height >>= 1; + } + } +} +#endif //USEFPM + +/* +=============== +R_ViewChanged + +Called every time the vid structure or r_refdef changes. +Guaranteed to be called before the first refresh +=============== +*/ +#ifndef USE_PQ_OPT +void R_ViewChanged (vrect_t *pvrect, int lineadj, float aspect) +{ + int i; + float res_scale; + + r_viewchanged = true; + + R_SetVrect (pvrect, &r_refdef.vrect, lineadj); + + r_refdef.horizontalFieldOfView = (float)(2.0 * tan (r_refdef.fov_x/360*M_PI)); + r_refdef.fvrectx = (float)r_refdef.vrect.x; + r_refdef.fvrectx_adj = (float)(r_refdef.vrect.x - 0.5); + r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1; + r_refdef.fvrecty = (float)r_refdef.vrect.y; + r_refdef.fvrecty_adj = (float)(r_refdef.vrect.y - 0.5); + r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width; + r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1; + r_refdef.fvrectright = (float)r_refdef.vrectright; + r_refdef.fvrectright_adj = (float)(r_refdef.vrectright - 0.5); + r_refdef.vrectrightedge = (float)(r_refdef.vrectright - 0.99); + r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height; + r_refdef.fvrectbottom = (float)r_refdef.vrectbottom; + r_refdef.fvrectbottom_adj = (float)(r_refdef.vrectbottom - 0.5); + + r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale); + r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale); + r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale); + r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale); + r_refdef.aliasvrectright = r_refdef.aliasvrect.x + + r_refdef.aliasvrect.width; + r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y + + r_refdef.aliasvrect.height; + + pixelAspect = aspect; + xOrigin = r_refdef.xOrigin; + yOrigin = r_refdef.yOrigin; + + screenAspect = r_refdef.vrect.width*pixelAspect / + r_refdef.vrect.height; +// 320*200 1.0 pixelAspect = 1.6 screenAspect +// 320*240 1.0 pixelAspect = 1.3333 screenAspect +// proper 320*200 pixelAspect = 0.8333333 + + verticalFieldOfView = r_refdef.horizontalFieldOfView / screenAspect; + +// values for perspective projection +// if math were exact, the values would range from 0.5 to to range+0.5 +// hopefully they wll be in the 0.000001 to range+.999999 and truncate +// the polygon rasterization will never render in the first row or column +// but will definately render in the [range] row and column, so adjust the +// buffer origin to get an exact edge to edge fill + xcenter = (float)(((float)r_refdef.vrect.width * XCENTERING) + + r_refdef.vrect.x - 0.5); + aliasxcenter = xcenter * r_aliasuvscale; + ycenter = (float)(((float)r_refdef.vrect.height * YCENTERING) + + r_refdef.vrect.y - 0.5); + aliasycenter = ycenter * r_aliasuvscale; + + xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView; + aliasxscale = xscale * r_aliasuvscale; + xscaleinv = (float)(1.0 / xscale); + yscale = xscale * pixelAspect; + aliasyscale = yscale * r_aliasuvscale; + yscaleinv = (float)(1.0 / yscale); + xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView; + yscaleshrink = xscaleshrink*pixelAspect; + +#ifdef USE_PQ_OPT1 + xscale_fxp=(int)(xscale*8388608.0); //9.23 + yscale_fxp=(int)(yscale*8388608.0); //9.23 + xcenter_fxp=(int)(xcenter*4194304.0); //10.22 + ycenter_fxp=(int)(ycenter*4194304.0); //10.22 + r_refdef_fvrectx_adj_fxp=(int)(r_refdef.fvrectx_adj*4194304.0); + r_refdef_fvrectright_adj_fxp=(int)(r_refdef.fvrectright_adj*4194304.0); + r_refdef_fvrecty_adj_fxp=(int)(r_refdef.fvrecty_adj*4194304.0); + r_refdef_fvrectbottom_adj_fxp=(int)(r_refdef.fvrectbottom_adj*4194304.0); +#endif + +// left side clip + screenedge[0].normal[0] = (float)(-1.0 / (xOrigin*r_refdef.horizontalFieldOfView)); + screenedge[0].normal[1] = 0; + screenedge[0].normal[2] = 1; + screenedge[0].type = PLANE_ANYZ; + +// right side clip + screenedge[1].normal[0] = + (float)(1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView)); + screenedge[1].normal[1] = 0; + screenedge[1].normal[2] = 1; + screenedge[1].type = PLANE_ANYZ; + +// top side clip + screenedge[2].normal[0] = 0; + screenedge[2].normal[1] = (float)(-1.0 / (yOrigin*verticalFieldOfView)); + screenedge[2].normal[2] = 1; + screenedge[2].type = PLANE_ANYZ; + +// bottom side clip + screenedge[3].normal[0] = 0; + screenedge[3].normal[1] = (float)(1.0 / ((1.0-yOrigin)*verticalFieldOfView)); + screenedge[3].normal[2] = 1; + screenedge[3].type = PLANE_ANYZ; + + for (i=0 ; i<4 ; i++) + VectorNormalize (screenedge[i].normal); + + res_scale = (float)(sqrt ((double)(r_refdef.vrect.width * r_refdef.vrect.height) / + (320.0 * 152.0)) * + (2.0 / r_refdef.horizontalFieldOfView)); + r_aliastransition = r_aliastransbase.value * res_scale; + r_resfudge = r_aliastransadj.value * res_scale; + + if (scr_fov.value <= 90.0) + r_fov_greater_than_90 = false; + else + r_fov_greater_than_90 = true; + +// TODO: collect 386-specific code in one place +#if id386 + if (r_pixbytes == 1) + { + Sys_MakeCodeWriteable ((long)R_Surf8Start, + (long)R_Surf8End - (long)R_Surf8Start); + colormap = vid.colormap; + R_Surf8Patch (); + } + else + { + Sys_MakeCodeWriteable ((long)R_Surf16Start, + (long)R_Surf16End - (long)R_Surf16Start); + colormap = vid.colormap16; + R_Surf16Patch (); + } +#endif // id386 + + D_ViewChanged (); +} +#else +//JB: Optimization +void R_ViewChanged (vrect_t *pvrect, int lineadj, float aspect) +{ + int i; + float res_scale; + + r_viewchanged = true; + + R_SetVrect (pvrect, &r_refdef.vrect, lineadj); + + r_refdef.horizontalFieldOfView = (float)(2.0 * tan (r_refdef.fov_x/360*M_PI)); + r_refdef.fvrectx = (float)r_refdef.vrect.x; + r_refdef.fvrectx_adj = (float)(r_refdef.vrect.x - 0.5); + r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1; + r_refdef.fvrecty = (float)r_refdef.vrect.y; + r_refdef.fvrecty_adj = (float)(r_refdef.vrect.y - 0.5); + r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width; + r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1; + r_refdef.fvrectright = (float)r_refdef.vrectright; + r_refdef.fvrectright_adj = (float)(r_refdef.vrectright - 0.5); + r_refdef.vrectrightedge = (float)(r_refdef.vrectright - 0.99); + r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height; + r_refdef.fvrectbottom = (float)r_refdef.vrectbottom; + r_refdef.fvrectbottom_adj = (float)(r_refdef.vrectbottom - 0.5); + + r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale); + r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale); + r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale); + r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale); + r_refdef.aliasvrectright = r_refdef.aliasvrect.x + + r_refdef.aliasvrect.width; + r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y + + r_refdef.aliasvrect.height; + + pixelAspect = aspect; + xOrigin = r_refdef.xOrigin; + yOrigin = r_refdef.yOrigin; + + screenAspect = r_refdef.vrect.width*pixelAspect / + r_refdef.vrect.height; +// 320*200 1.0 pixelAspect = 1.6 screenAspect +// 320*240 1.0 pixelAspect = 1.3333 screenAspect +// proper 320*200 pixelAspect = 0.8333333 + + verticalFieldOfView = r_refdef.horizontalFieldOfView / screenAspect; + +// values for perspective projection +// if math were exact, the values would range from 0.5 to to range+0.5 +// hopefully they wll be in the 0.000001 to range+.999999 and truncate +// the polygon rasterization will never render in the first row or column +// but will definately render in the [range] row and column, so adjust the +// buffer origin to get an exact edge to edge fill + xcenter = (float)(((float)r_refdef.vrect.width * XCENTERING) + + r_refdef.vrect.x - 0.5); + fpxcenter = (int)(64.0f * xcenter); + aliasxcenter = xcenter * r_aliasuvscale; + ycenter = (float)(((float)r_refdef.vrect.height * YCENTERING) + + r_refdef.vrect.y - 0.5); + fpycenter = (int)(64.0f * ycenter); + aliasycenter = ycenter * r_aliasuvscale; + + xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView; + aliasxscale = xscale * r_aliasuvscale; + xscaleinv = (float)(1.0 / xscale); + yscale = xscale * pixelAspect; + fpxscale = (int)(1024.0f * xscale); + fpyscale = (int)(1024.0f * yscale); + aliasyscale = yscale * r_aliasuvscale; + yscaleinv = (float)(1.0 / yscale); + xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView; + yscaleshrink = xscaleshrink*pixelAspect; + +#ifdef USE_PQ_OPT1 + xscale_fxp=(int)(xscale*8388608.0); + yscale_fxp=(int)(yscale*8388608.0); + xcenter_fxp=(int)(xcenter*8388608.0); + ycenter_fxp=(int)(ycenter*8388608.0); + r_refdef_fvrectx_adj_fxp=(int)(r_refdef.fvrectx_adj*8388608.0); + r_refdef_fvrectright_adj_fxp=(int)(r_refdef.fvrectright_adj*8388608.0); + r_refdef_fvrecty_adj_fxp=(int)(r_refdef.fvrecty_adj*8388608.0); + r_refdef_fvrectbottom_adj_fxp=(int)(r_refdef.fvrectbottom_adj*8388608.0); +#endif + +// left side clip + screenedge[0].normal[0] = (float)(-1.0 / (xOrigin*r_refdef.horizontalFieldOfView)); + screenedge[0].normal[1] = 0; + screenedge[0].normal[2] = 1; + screenedge[0].type = PLANE_ANYZ; + +// right side clip + screenedge[1].normal[0] = + (float)(1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView)); + screenedge[1].normal[1] = 0; + screenedge[1].normal[2] = 1; + screenedge[1].type = PLANE_ANYZ; + +// top side clip + screenedge[2].normal[0] = 0; + screenedge[2].normal[1] = (float)(-1.0 / (yOrigin*verticalFieldOfView)); + screenedge[2].normal[2] = 1; + screenedge[2].type = PLANE_ANYZ; + +// bottom side clip + screenedge[3].normal[0] = 0; + screenedge[3].normal[1] = (float)(1.0 / ((1.0-yOrigin)*verticalFieldOfView)); + screenedge[3].normal[2] = 1; + screenedge[3].type = PLANE_ANYZ; + + for (i=0 ; i<4 ; i++) + VectorNormalize (screenedge[i].normal); + + res_scale = (float)(sqrt ((double)(r_refdef.vrect.width * r_refdef.vrect.height) / + (320.0 * 152.0)) * + (2.0 / r_refdef.horizontalFieldOfView)); + r_aliastransition = r_aliastransbase.value * res_scale; + r_resfudge = r_aliastransadj.value * res_scale; + + if (scr_fov.value <= 90.0) + r_fov_greater_than_90 = false; + else + r_fov_greater_than_90 = true; + +// TODO: collect 386-specific code in one place +#if id386 + if (r_pixbytes == 1) + { + Sys_MakeCodeWriteable ((long)R_Surf8Start, + (long)R_Surf8End - (long)R_Surf8Start); + colormap = vid.colormap; + R_Surf8Patch (); + } + else + { + Sys_MakeCodeWriteable ((long)R_Surf16Start, + (long)R_Surf16End - (long)R_Surf16Start); + colormap = vid.colormap16; + R_Surf16Patch (); + } +#endif // id386 + + D_ViewChanged (); +} +#endif +/* +=============== +R_MarkLeaves +=============== +*/ +void R_MarkLeaves (void) +{ + byte *vis; + mnode_t *node; + int i; + + if (r_oldviewleaf == r_viewleaf) + return; + + r_visframecount++; + r_oldviewleaf = r_viewleaf; + + vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel); + + for (i=0 ; inumleafs ; i++) + { + if (vis[i>>3] & (1<<(i&7))) + { + node = (mnode_t *)&cl.worldmodel->leafs[i+1]; + do + { + if (node->visframe == r_visframecount) + break; + node->visframe = r_visframecount; + node = node->parent; + } while (node); + } + } +} + +#ifdef USEFPM +void R_MarkLeavesFPM (void) +{ + byte *vis; + mnode_FPM_t *node; + int i; + + if (r_oldviewleafFPM == r_viewleafFPM) + return; + + r_visframecount++; + r_oldviewleafFPM = r_viewleafFPM; + + vis = Mod_LeafPVSFPM (r_viewleafFPM, clFPM.worldmodel); + + for (i=0 ; inumleafs ; i++) + { + if (vis[i>>3] & (1<<(i&7))) + { + node = (mnode_FPM_t *)&clFPM.worldmodel->leafs[i+1]; + do + { + if (node->visframe == r_visframecount) + break; + node->visframe = r_visframecount; + node = node->parent; + } while (node); + } + } +} +#endif //USEFPM + +/* +============= +R_DrawEntitiesOnList +============= +*/ +void R_DrawEntitiesOnList (void) +{ + int i, j; + int lnum; + alight_t lighting; +// FIXME: remove and do real lighting + float lightvec[3] = {-1, 0, 0}; + vec3_t dist; + float add; + + if (!r_drawentities.value) + return; + + for (i=0 ; imodel->type) + { + case mod_sprite: + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + R_DrawSprite (); + break; + + case mod_alias: + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + + // see if the bounding box lets us trivially reject, also sets + // trivial accept status + + if (R_AliasCheckBBox ()) + { + + j = R_LightPoint (currententity->origin); + + lighting.ambientlight = j; + lighting.shadelight = j; + + lighting.plightvec = lightvec; + + for (lnum=0 ; lnum= cl.time) + { + VectorSubtract (currententity->origin, + cl_dlights[lnum].origin, + dist); + add = cl_dlights[lnum].radius - Length(dist); + + if (add > 0) + lighting.ambientlight += (int)add; + } + } + + + // clamp lighting so it doesn't overbright as much + if (lighting.ambientlight > 128) + lighting.ambientlight = 128; + if (lighting.ambientlight + lighting.shadelight > 192) + lighting.shadelight = 192 - lighting.ambientlight; + + R_AliasDrawModel (&lighting); + } + + break; + + default: + break; + } + } +} + +#ifdef USEFPM +void R_DrawEntitiesOnListFPM (void) +{ + int i, j; + int lnum; + alight_FPM_t lighting; +// FIXME: remove and do real lighting (not Dan's comment) + fixedpoint_t lightvec[3] = {FPM_FROMLONGC(-1), 0, 0}; + vec3_FPM_t dist; + fixedpoint_t add; + + if (!r_drawentities.value) + return; + + for (i=0 ; imodel->type) + { + case mod_sprite: + VectorCopy (currententityFPM->origin, r_entoriginFPM); + VectorSubtractFPM (r_originFPM, r_entoriginFPM, modelorgFPM); + R_DrawSpriteFPM (); + break; + + case mod_alias: + VectorCopy (currententityFPM->origin, r_entoriginFPM); + VectorSubtractFPM (r_originFPM, r_entoriginFPM, modelorgFPM); + + // see if the bounding box lets us trivially reject, also sets + // trivial accept status + if (R_AliasCheckBBoxFPM ()) + { + j = R_LightPointFPM (currententityFPM->origin); + + lighting.ambientlight = j; + lighting.shadelight = j; + + lighting.plightvec = lightvec; + + for (lnum=0 ; lnum= cl.time) + { + VectorSubtractFPM (currententityFPM->origin, + cl_dlightsFPM[lnum].origin, + dist); + add = cl_dlightsFPM[lnum].radius - LengthFPM(dist); + + if (add > 0) + lighting.ambientlight += (int)add; + } + } + + // clamp lighting so it doesn't overbright as much + if (lighting.ambientlight > 128) + lighting.ambientlight = 128; + if (lighting.ambientlight + lighting.shadelight > 192) + lighting.shadelight = 192 - lighting.ambientlight; + + R_AliasDrawModelFPM (&lighting); + } + + break; + + default: + break; + } + } +} +#endif //USEFPM + +/* +============= +R_DrawViewModel +============= +*/ +void R_DrawViewModel (void) +{ +// FIXME: remove and do real lighting + float lightvec[3] = {-1, 0, 0}; + int j; + int lnum; + vec3_t dist; + float add; + dlight_t *dl; + + if (!r_drawviewmodel.value || r_fov_greater_than_90) + return; + + if (cl.items & IT_INVISIBILITY) + return; + + if (cl.stats[STAT_HEALTH] <= 0) + return; + + currententity = &cl.viewent; + if (!currententity->model) + return; + + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + + VectorCopy (vup, viewlightvec); + VectorInverse (viewlightvec); + + j = R_LightPoint (currententity->origin); + + if (j < 24) + j = 24; // allways give some light on gun + r_viewlighting.ambientlight = j; + r_viewlighting.shadelight = j; + +// add dynamic lights + for (lnum=0 ; lnumradius) + continue; + if (!dl->radius) + continue; + if (dl->die < cl.time) + continue; + + VectorSubtract (currententity->origin, dl->origin, dist); + add = dl->radius - Length(dist); + if (add > 0) + r_viewlighting.ambientlight += (int)add; + } + +// clamp lighting so it doesn't overbright as much + if (r_viewlighting.ambientlight > 128) + r_viewlighting.ambientlight = 128; + if (r_viewlighting.ambientlight + r_viewlighting.shadelight > 192) + r_viewlighting.shadelight = 192 - r_viewlighting.ambientlight; + + r_viewlighting.plightvec = lightvec; + +#ifdef QUAKE2 + cl.light_level = r_viewlighting.ambientlight; +#endif + + R_AliasDrawModel (&r_viewlighting); +} + +#ifdef USEFPM +void R_DrawViewModelFPM (void) +{ +// FIXME: remove and do real lighting + fixedpoint_t lightvec[3] = {FPM_FROMLONG(-1), 0, 0}; + int j; + int lnum; + vec3_FPM_t dist; + fixedpoint_t add; + dlight_FPM_t *dl; + + if (!r_drawviewmodel.value || r_fov_greater_than_90) + return; + + if (clFPM.items & IT_INVISIBILITY) + return; + + if (clFPM.stats[STAT_HEALTH] <= 0) + return; + + currententityFPM = &clFPM.viewent; + if (!currententityFPM->model) + return; + + VectorCopy (currententityFPM->origin, r_entoriginFPM); + VectorSubtractFPM (r_originFPM, r_entoriginFPM, modelorgFPM); + + VectorCopy (vupFPM, viewlightvecFPM); + VectorInverseFPM (viewlightvecFPM); + + j = R_LightPointFPM (currententityFPM->origin); + + if (j < 24) + j = 24; // allways give some light on gun + r_viewlightingFPM.ambientlight = j; + r_viewlightingFPM.shadelight = j; + +// add dynamic lights + for (lnum=0 ; lnumradius) + continue; + if (!dl->radius) + continue; + if (dl->die < cl.time) + continue; + + VectorSubtractFPM (currententityFPM->origin, dl->origin, dist); + add = dl->radius - LengthFPM(dist); + if (add > 0) + r_viewlightingFPM.ambientlight += (int)add; + } + +// clamp lighting so it doesn't overbright as much + if (r_viewlightingFPM.ambientlight > 128) + r_viewlightingFPM.ambientlight = 128; + if (r_viewlightingFPM.ambientlight + r_viewlightingFPM.shadelight > 192) + r_viewlightingFPM.shadelight = 192 - r_viewlightingFPM.ambientlight; + + r_viewlightingFPM.plightvec = lightvec; + +#ifdef QUAKE2 + clFPM.light_level = r_viewlightingFPM.ambientlight; +#endif + + R_AliasDrawModelFPM (&r_viewlightingFPM); +} +#endif //USEFPM + +/* +============= +R_BmodelCheckBBox +============= +*/ +int R_BmodelCheckBBox (model_t *clmodel, float *minmaxs) +{ + int i, *pindex, clipflags; + vec3_t acceptpt, rejectpt; + double d; + + clipflags = 0; + + if (currententity->angles[0] || currententity->angles[1] + || currententity->angles[2]) + { + for (i=0 ; i<4 ; i++) + { + d = DotProduct (currententity->origin, view_clipplanes[i].normal); + d -= view_clipplanes[i].dist; + + if (d <= -clmodel->radius) + return BMODEL_FULLY_CLIPPED; + + if (d <= clmodel->radius) + clipflags |= (1<angles[0] || currententityFPM->angles[1] + || currententityFPM->angles[2]) + { + for (i=0 ; i<4 ; i++) + { + d = DotProductFPM (currententityFPM->origin, view_clipplanesFPM[i].normal); + d = FPM_SUB(d, view_clipplanesFPM[i].dist); + + if (d <= -clmodel->radius) + return BMODEL_FULLY_CLIPPED; + + if (d <= clmodel->radius) + clipflags |= (1< 32.32 + accum-=mul; + if (accum<=0) + return BMODEL_FULLY_CLIPPED; + + //d = DotProductFPM (rejectpt, view_clipplanesFPM[i].normal); + //d = FPM_SUB(d, view_clipplanesFPM[i].dist); + + //if (d <= 0) + // return BMODEL_FULLY_CLIPPED; + + acceptpt[0] = minmaxs[pindex[3+0]]; + acceptpt[1] = minmaxs[pindex[3+1]]; + acceptpt[2] = minmaxs[pindex[3+2]]; + + accum=acceptpt[0]; + accum*=view_clipplanesFPM[i].normal[0]; + mul=acceptpt[1]; + mul*=view_clipplanesFPM[i].normal[1]; + accum+=mul; + mul=acceptpt[2]; + mul*=view_clipplanesFPM[i].normal[2]; + accum+=mul; + mul=view_clipplanesFPM[i].dist; + mul<<=16; //16.16 -> 32.32 + accum-=mul; + if (accum <= 0) + clipflags |= (1<model->type) + { + case mod_brush: + + clmodel = currententity->model; + + // see if the bounding box lets us trivially reject, also sets + // trivial accept status + for (j=0 ; j<3 ; j++) + { + minmaxs[j] = currententity->origin[j] + + clmodel->mins[j]; + minmaxs[3+j] = currententity->origin[j] + + clmodel->maxs[j]; + } + + clipflags = R_BmodelCheckBBox (clmodel, minmaxs); + + if (clipflags != BMODEL_FULLY_CLIPPED) + { + VectorCopy (currententity->origin, r_entorigin); + VectorSubtract (r_origin, r_entorigin, modelorg); + // FIXME: is this needed? + VectorCopy (modelorg, r_worldmodelorg); + + r_pcurrentvertbase = clmodel->vertexes; + +#ifdef USE_PQ_OPT2 + r_pcurrentvertbase_fxp = clmodel->vertexes_fxp; +#endif + // FIXME: stop transforming twice + R_RotateBmodel (); + +#ifdef USE_PQ_OPT1 + modelorg_fxp[0]=(int)(modelorg[0]*524288.0); + modelorg_fxp[1]=(int)(modelorg[1]*524288.0); + modelorg_fxp[2]=(int)(modelorg[2]*524288.0); + + vright_fxp[0]=(int)(256.0/vright[0]); + if (!vright_fxp[0]) vright_fxp[0]=0x7fffffff; + vright_fxp[1]=(int)(256.0/vright[1]); + if (!vright_fxp[1]) vright_fxp[1]=0x7fffffff; + vright_fxp[2]=(int)(256.0/vright[2]); + if (!vright_fxp[2]) vright_fxp[2]=0x7fffffff; + + vpn_fxp[0]=(int)(256.0/vpn[0]); + if (!vpn_fxp[0]) vpn_fxp[0]=0x7fffffff; + vpn_fxp[1]=(int)(256.0/vpn[1]); + if (!vpn_fxp[1]) vpn_fxp[1]=0x7fffffff; + vpn_fxp[2]=(int)(256.0/vpn[2]); + if (!vpn_fxp[2]) vpn_fxp[2]=0x7fffffff; + + vup_fxp[0]=(int)(256.0/vup[0]); + if (!vup_fxp[0]) vup_fxp[0]=0x7fffffff; + vup_fxp[1]=(int)(256.0/vup[1]); + if (!vup_fxp[1]) vup_fxp[1]=0x7fffffff; + vup_fxp[2]=(int)(256.0/vup[2]); + if (!vup_fxp[2]) vup_fxp[2]=0x7fffffff; +#endif + + // calculate dynamic lighting for bmodel if it's not an + // instanced model + if (clmodel->firstmodelsurface != 0) + { + for (k=0 ; knodes + clmodel->hulls[0].firstclipnode); + } + } + + // if the driver wants polygons, deliver those. Z-buffering is on + // at this point, so no clipping to the world tree is needed, just + // frustum clipping + if (r_drawpolys | r_drawculledpolys) + { + R_ZDrawSubmodelPolys (clmodel); + } + else + { + r_pefragtopnode = NULL; + + for (j=0 ; j<3 ; j++) + { + r_emins[j] = minmaxs[j]; + r_emaxs[j] = minmaxs[3+j]; + } + + R_SplitEntityOnNode2 (cl.worldmodel->nodes); + + if (r_pefragtopnode) + { + currententity->topnode = r_pefragtopnode; + + if (r_pefragtopnode->contents >= 0) + { + // not a leaf; has to be clipped to the world BSP + r_clipflags = clipflags; + R_DrawSolidClippedSubmodelPolygons (clmodel); + } + else + { + // falls entirely in one leaf, so we just put all the + // edges in the edge list and let 1/z sorting handle + // drawing order + R_DrawSubmodelPolygons (clmodel, clipflags); + } + + currententity->topnode = NULL; + } + } + + // put back world rotation and frustum clipping + // FIXME: R_RotateBmodel should just work off base_vxx + VectorCopy (base_vpn, vpn); + VectorCopy (base_vup, vup); + VectorCopy (base_vright, vright); + VectorCopy (base_modelorg, modelorg); + VectorCopy (oldorigin, modelorg); + R_TransformFrustum (); + } + + break; + + default: + break; + } + } + + insubmodel = false; + +} + + +//extern edge_t *ledges; +//extern surf_t *lsurfs; + + +/* +================ +R_EdgeDrawing +================ +*/ +void R_EdgeDrawing (void) +{ + /* + edge_t ledges[NUMSTACKEDGES + ((CACHE_SIZE - 1) / sizeof(edge_t)) + 1]; + surf_t lsurfs[NUMSTACKSURFACES + ((CACHE_SIZE - 1) / sizeof(surf_t)) + 1]; + edge_t *ledges; + surf_t *lsurfs; + ledges = malloc( (sizeof(edge_t)*NUMSTACKEDGES) + (sizeof(edge_t)*(((CACHE_SIZE - 1) / sizeof(edge_t)) + 1))); + lsurfs = malloc( (sizeof(edge_t)*NUMSTACKSURFACES) + (sizeof(edge_t)*(((CACHE_SIZE - 1) / sizeof(surf_t)) + 1))); + */ + +#ifdef USEFPM + edge_FPM_t ledges[NUMSTACKEDGES + + ((CACHE_SIZE - 1) / sizeof(edge_FPM_t)) + 1]; + surf_FPM_t lsurfs[NUMSTACKSURFACES + + ((CACHE_SIZE - 1) / sizeof(surf_FPM_t)) + 1]; +#else + edge_t ledges[NUMSTACKEDGES + ((CACHE_SIZE - 1) / sizeof(edge_t)) + 1]; + surf_t lsurfs[NUMSTACKSURFACES + ((CACHE_SIZE - 1) / sizeof(surf_t)) + 1]; + +#endif + + // Cache_Report(); + + + if (auxedges) + { + r_edges = auxedges; + } + else + { + r_edges = (edge_t *) + (((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + } + + if (r_surfsonstack) + { + surfaces = (surf_t *) + (((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + surf_max = &surfaces[r_cnumsurfs]; + // surface 0 doesn't really exist; it's just a dummy because index 0 + // is used to indicate no edge attached to surface + surfaces--; + R_SurfacePatch (); + } + + // Cache_Report(); + + R_BeginEdgeFrame (); + + if (r_dspeeds.value) + { + rw_time1 = (float)Sys_FloatTime (); + } + + // Cache_Report(); + + R_RenderWorld (); + + if (r_drawculledpolys){ + R_ScanEdges (); + } + +// only the world can be drawn back to front with no z reads or compares, just +// z writes, so have the driver turn z compares on now + D_TurnZOn (); + + if (r_dspeeds.value) + { + rw_time2 = (float)Sys_FloatTime (); + db_time1 = rw_time2; + } + + // Cache_Report(); + + R_DrawBEntitiesOnList (); + + if (r_dspeeds.value) + { + db_time2 = (float)Sys_FloatTime (); + se_time1 = db_time2; + } + + if (!r_dspeeds.value) + { + VID_UnlockBuffer (); + S_ExtraUpdate (); // don't let sound get messed up if going slow + VID_LockBuffer (); + } + + // Cache_Report(); + + + if (!(r_drawpolys | r_drawculledpolys)) { + R_ScanEdges (); + } + + /* free(ledges); + free(lsurfs); + */ + +} + +#ifdef USEFPM +void R_EdgeDrawingFPM (void) +{ + +// int i=NUMSTACKEDGES + +// ((CACHE_SIZE - 1) / sizeof(edge_t)) + 1; + + if (auxedgesFPM) + { + r_edgesFPM = auxedgesFPM; + } + else + { + r_edgesFPM = (edge_FPM_t *) + (((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + } + + if (r_surfsonstack) + { + surfacesFPM = (surf_FPM_t *) + (((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1)); + surf_maxFPM = &surfacesFPM[r_cnumsurfs]; + // surface 0 doesn't really exist; it's just a dummy because index 0 + // is used to indicate no edge attached to surface + surfacesFPM--; + R_SurfacePatchFPM (); + } + + R_BeginEdgeFrameFPM (); + + if (r_dspeeds.value) + { + rw_time1 = (float)Sys_FloatTime (); + } + + //R_RenderWorldFPM (); // FPM doesn't exist + R_RenderWorld (); + + if (r_drawculledpolys) + R_ScanEdgesFPM (); + +// only the world can be drawn back to front with no z reads or compares, just +// z writes, so have the driver turn z compares on now + //D_TurnZOn (); //Dan: empty func + + if (r_dspeeds.value) + { + rw_time2 = (float)Sys_FloatTime (); + db_time1 = rw_time2; + } + + //R_DrawBEntitiesOnListFPM (); // FPM doesn't exist + R_DrawBEntitiesOnList (); + + if (r_dspeeds.value) + { + db_time2 = (float)Sys_FloatTime (); + se_time1 = db_time2; + } + + if (!r_dspeeds.value) + { + VID_UnlockBuffer (); + S_ExtraUpdate (); // don't let sound get messed up if going slow + VID_LockBuffer (); + } + + if (!(r_drawpolys | r_drawculledpolys)) + R_ScanEdgesFPM (); + +} +#endif //USEFPM + +extern int r_numparticles, r_allocatedparticles; +/* +================ +R_RenderView + +r_refdef must be set before the first call +================ +*/ + + +void R_RenderView_ (void) +{ +byte warpbuffer[WARP_WIDTH * WARP_HEIGHT]; + //Dan: + // byte warpbuffer[WARP_WIDTH * WARP_HEIGHT]; + + //Dan East: Here we see if the new r_maxparticles var has changed, + //if so we change the max value. I guess this is as good a place + //as any to perform this check. + if (r_numparticles != (int)r_maxparticles.value) { + r_numparticles = (int)r_maxparticles.value; + //Check to see if we have enough particles allocated + if (r_numparticles>=r_allocatedparticles) + //We don't (they've exceeded MAX_PARTICLES or the original -particles value) + r_numparticles=r_allocatedparticles; + R_ClearParticles(); + } + + r_warpbuffer = warpbuffer; + + if (r_timegraph.value || r_speeds.value || r_dspeeds.value) + r_time1 = (float)Sys_FloatTime (); + + R_SetupFrame (); + +#ifdef PASSAGES + SetVisibilityByPassages (); +#else + R_MarkLeaves (); // done here so we know if we're in water +#endif + +// make FDIV fast. This reduces timing precision after we've been running for a +// while, so we don't do it globally. This also sets chop mode, and we do it +// here so that setup stuff like the refresh area calculations match what's +// done in screen.c +// Sys_LowFPPrecision (); + + if (!cl_entities[0].model || !cl.worldmodel) + Sys_Error ("R_RenderView: NULL worldmodel"); + + if (!r_dspeeds.value) + { + VID_UnlockBuffer (); + S_ExtraUpdate (); // don't let sound get messed up if going slow + VID_LockBuffer (); + } + + R_EdgeDrawing (); + + if (!r_dspeeds.value) + { + VID_UnlockBuffer (); + S_ExtraUpdate (); // don't let sound get messed up if going slow + VID_LockBuffer (); + } + + if (r_dspeeds.value) + { + se_time2 = (float)Sys_FloatTime (); + de_time1 = se_time2; + } + + R_DrawEntitiesOnList (); + + if (r_dspeeds.value) + { + de_time2 = (float)Sys_FloatTime (); + dv_time1 = de_time2; + } + + R_DrawViewModel (); + + if (r_dspeeds.value) + { + dv_time2 = (float)Sys_FloatTime (); + dp_time1 = (float)Sys_FloatTime (); + } + + R_DrawParticles (); + + if (r_dspeeds.value) + dp_time2 = (float)Sys_FloatTime (); + + + if (r_dowarp) + D_WarpScreen (); + + + V_SetContentsColor (r_viewleaf->contents); + + + if (r_timegraph.value) + R_TimeGraph (); + + if (r_aliasstats.value) + R_PrintAliasStats (); + + if (r_speeds.value) + R_PrintTimes (); + + if (r_dspeeds.value) + R_PrintDSpeeds (); + + if (r_reportsurfout.value && r_outofsurfaces) + Con_Printf ("Short %d surfaces\n", r_outofsurfaces); + + if (r_reportedgeout.value && r_outofedges) + Con_Printf ("Short roughly %d edges\n", r_outofedges * 2 / 3); + +// back to high floating-point precision +// Sys_HighFPPrecision (); + +} + +#ifdef USEFPM +void R_RenderViewFPM_ (void) +{ + //Dan: +// byte *warpbuffer=malloc(WARP_WIDTH * WARP_HEIGHT); +// byte warpbuffer[WARP_WIDTH * WARP_HEIGHT]; + + r_warpbuffer = warpbuffer; + + if (r_timegraph.value || r_speeds.value || r_dspeeds.value) + r_time1 = (float)Sys_FloatTime (); + + // R_SetupFrameFPM (); // FPM doesn't exist + R_SetupFrame (); + +#ifdef PASSAGES + SetVisibilityByPassages (); +#else + R_MarkLeavesFPM (); // done here so we know if we're in water +#endif + +// make FDIV fast. This reduces timing precision after we've been running for a +// while, so we don't do it globally. This also sets chop mode, and we do it +// here so that setup stuff like the refresh area calculations match what's +// done in screen.c + Sys_LowFPPrecision (); + + if (!cl_entitiesFPM[0].model || !clFPM.worldmodel) + Sys_Error ("R_RenderView: NULL worldmodel"); + + if (!r_dspeeds.value) + { + VID_UnlockBuffer (); + S_ExtraUpdate (); // don't let sound get messed up if going slow + VID_LockBuffer (); + } + + R_EdgeDrawingFPM (); + + if (!r_dspeeds.value) + { + VID_UnlockBuffer (); + S_ExtraUpdate (); // don't let sound get messed up if going slow + VID_LockBuffer (); + } + + if (r_dspeeds.value) + { + se_time2 = (float)Sys_FloatTime (); + de_time1 = se_time2; + } + + R_DrawEntitiesOnListFPM (); + + if (r_dspeeds.value) + { + de_time2 = (float)Sys_FloatTime (); + dv_time1 = de_time2; + } + + R_DrawViewModelFPM (); + + if (r_dspeeds.value) + { + dv_time2 = (float)Sys_FloatTime (); + dp_time1 = (float)Sys_FloatTime (); + } + + R_DrawParticlesFPM (); + + if (r_dspeeds.value) + dp_time2 = (float)Sys_FloatTime (); + + if (r_dowarp) + D_WarpScreen (); + + V_SetContentsColorFPM (r_viewleafFPM->contents); + + if (r_timegraph.value) + //R_TimeGraphFPM (); // FPM doesn't exist + R_TimeGraph (); + + if (r_aliasstats.value) + R_PrintAliasStats (); + + if (r_speeds.value) + R_PrintTimes (); + + if (r_dspeeds.value) + R_PrintDSpeeds (); + + if (r_reportsurfout.value && r_outofsurfaces) + Con_Printf ("Short %d surfaces\n", r_outofsurfaces); + + if (r_reportedgeout.value && r_outofedges) + Con_Printf ("Short roughly %d edges\n", r_outofedges * 2 / 3); + +// back to high floating-point precision + Sys_HighFPPrecision (); +} +#endif //USEFPM + +void R_RenderView (void) +{ + int dummy; + int delta; + + delta = (byte *)&dummy - r_stack_start; + if (delta < -10000 || delta > 10000) + Sys_Error ("R_RenderView: called without enough stack"); + + if ( Hunk_LowMark() & 3 ) + Sys_Error ("Hunk is missaligned"); + + if ( (long)(&dummy) & 3 ) + Sys_Error ("Stack is missaligned"); + + if ( (long)(&r_warpbuffer) & 3 ) + Sys_Error ("Globals are missaligned"); + + R_RenderView_ (); +} + +#ifdef USEFPM +void R_RenderViewFPM (void) +{ + int dummy; + int delta; + + delta = (byte *)&dummy - r_stack_start; + if (delta < -10000 || delta > 10000) + Sys_Error ("R_RenderView: called without enough stack"); + + if ( Hunk_LowMark() & 3 ) + Sys_Error ("Hunk is missaligned"); + + if ( (long)(&dummy) & 3 ) + Sys_Error ("Stack is missaligned"); + + if ( (long)(&r_warpbuffer) & 3 ) + Sys_Error ("Globals are missaligned"); + + R_RenderViewFPM_ (); +} +#endif //USEFPM + +/* +================ +R_InitTurb +================ +*/ +void R_InitTurb (void) +{ + int i; + + for (i=0 ; i<(SIN_BUFFER_SIZE) ; i++) + { + sintable[i] = (int)(AMP + sin(i*3.14159*2/CYCLE)*AMP); + intsintable[i] = (int)(AMP2 + sin(i*3.14159*2/CYCLE)*AMP2); // AMP2, not 20 + } +} + diff --git a/project/jni/application/quake/source/r_misc.c b/project/jni/application/quake/source/r_misc.c new file mode 100644 index 000000000..58485bd9e --- /dev/null +++ b/project/jni/application/quake/source/r_misc.c @@ -0,0 +1,568 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_misc.c + +#include "quakedef.h" +#include "r_local.h" + + +/* +=============== +R_CheckVariables +=============== +*/ +void R_CheckVariables (void) +{ + static float oldbright; + + if (r_fullbright.value != oldbright) + { + oldbright = r_fullbright.value; + D_FlushCaches (); // so all lighting changes + } +} + +/* +============ +Show + +Debugging use +============ +*/ +void Show (void) +{ + vrect_t vr; + + vr.x = vr.y = 0; + vr.width = vid.width; + vr.height = vid.height; + vr.pnext = NULL; + VID_Update (&vr); +} + +/* +==================== +R_TimeRefresh_f + +For program optimization +==================== +*/ +void R_TimeRefresh_f (void) +{ + int i; + float start, stop, time; + int startangle; + vrect_t vr; + + startangle = (int)r_refdef.viewangles[1]; + + start = (float)Sys_FloatTime (); + for (i=0 ; i<128 ; i++) + { + r_refdef.viewangles[1] = (float)(i/128.0*360.0); + + VID_LockBuffer (); + + R_RenderView (); + + VID_UnlockBuffer (); + + vr.x = r_refdef.vrect.x; + vr.y = r_refdef.vrect.y; + vr.width = r_refdef.vrect.width; + vr.height = r_refdef.vrect.height; + vr.pnext = NULL; + VID_Update (&vr); + } + stop = (float)Sys_FloatTime (); + time = stop-start; + Con_Printf ("%f seconds (%f fps)\n", time, 128/time); + + r_refdef.viewangles[1] = (float)startangle; +} + + +/* +================ +R_LineGraph + +Only called by R_DisplayTime +================ +*/ +void R_LineGraph (int x, int y, int h) +{ + int i; + byte *dest; + int s; + +// FIXME: should be disabled on no-buffer adapters, or should be in the driver + + x += r_refdef.vrect.x; + y += r_refdef.vrect.y; + + dest = vid.buffer + vid.rowbytes*y + x; + + s = (int)r_graphheight.value; + + if (h>s) + h = s; + + for (i=0 ; i> 4; + out[1] = (in[0] * fpvup[0] + + in[1] * fpvup[1] + + in[2] * fpvup[2]) >> 4; + out[2] = (in[0] * fpvpn[0] + + in[1] * fpvpn[1] + + in[2] * fpvpn[2]) >> 4; +} + +#endif +#endif + + +/* +================ +R_TransformPlane +================ +*/ +void R_TransformPlane (mplane_t *p, float *normal, float *dist) +{ + float d; + + d = DotProduct (r_origin, p->normal); + *dist = p->dist - d; +// TODO: when we have rotating entities, this will need to use the view matrix + TransformVector (p->normal, normal); +} + +/* +=============== +R_SetUpFrustumIndexes +=============== +*/ +void R_SetUpFrustumIndexes (void) +{ + static int i, j, *pindex; + + pindex = r_frustum_indexes; + + for (i=0 ; i<4 ; i++) + { + for (j=0 ; j<3 ; j++) + { + if (view_clipplanes[i].normal[j] < 0.0) + { + pindex[j] = j; + pindex[j+3] = j+3; + //Dan: +// pindex[j+1]=pindex[j+2]=0; + } + else + { + pindex[j] = j+3; + pindex[j+3] = j; +// pindex[j+1]=pindex[j+2]=0; + } + } + // FIXME: do just once at start + pfrustum_indexes[i] = pindex; + pindex += 6; + } + +// VerifyFrustumIndexes("setup"); +} + + +/* +=============== +R_SetupFrame +=============== +*/ +void R_SetupFrame (void) +{ + int edgecount; + vrect_t vrect; + float w, h; + +// don't allow cheats in multiplayer + if (cl.maxclients > 1) + { + Cvar_Set ("r_draworder", "0"); + Cvar_Set ("r_fullbright", "0"); + Cvar_Set ("r_ambient", "0"); + Cvar_Set ("r_drawflat", "0"); + } + + if (r_numsurfs.value) + { + if ((surface_p - surfaces) > r_maxsurfsseen) + r_maxsurfsseen = surface_p - surfaces; + + Con_Printf ("Used %d of %d surfs; %d max\n", surface_p - surfaces, + surf_max - surfaces, r_maxsurfsseen); + } + + if (r_numedges.value) + { + edgecount = edge_p - r_edges; + + if (edgecount > r_maxedgesseen) + r_maxedgesseen = edgecount; + + Con_Printf ("Used %d of %d edges; %d max\n", edgecount, + r_numallocatededges, r_maxedgesseen); + } + + r_refdef.ambientlight = (int)r_ambient.value; + + if (r_refdef.ambientlight < 0) + r_refdef.ambientlight = 0; + + if (!sv.active) + r_draworder.value = 0; // don't let cheaters look behind walls + + R_CheckVariables (); + + R_AnimateLight (); + + r_framecount++; + + numbtofpolys = 0; + +// debugging +#if 0 +r_refdef.vieworg[0]= 80; +r_refdef.vieworg[1]= 64; +r_refdef.vieworg[2]= 40; +r_refdef.viewangles[0]= 0; +r_refdef.viewangles[1]= 46.763641357; +r_refdef.viewangles[2]= 0; +#endif + +// build the transformation matrix for the given view angles + VectorCopy (r_refdef.vieworg, modelorg); + VectorCopy (r_refdef.vieworg, r_origin); + + AngleVectors (r_refdef.viewangles, vpn, vright, vup); + +// current viewleaf + r_oldviewleaf = r_viewleaf; + r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel); + + r_dowarpold = r_dowarp; + r_dowarp = r_waterwarp.value && (r_viewleaf->contents <= CONTENTS_WATER); + + if ((r_dowarp != r_dowarpold) || r_viewchanged || lcd_x.value) + { + if (r_dowarp) + { + if ((vid.width <= (unsigned int)vid.maxwarpwidth) && + (vid.height <= (unsigned int)vid.maxwarpheight)) + { + vrect.x = 0; + vrect.y = 0; + vrect.width = vid.width; + vrect.height = vid.height; + + R_ViewChanged (&vrect, sb_lines, vid.aspect); + } + else + { + w = (float)vid.width; + h = (float)vid.height; + + if (w > vid.maxwarpwidth) + { + h *= (float)vid.maxwarpwidth / w; + w = (float)vid.maxwarpwidth; + } + + if (h > vid.maxwarpheight) + { + h = (float)vid.maxwarpheight; + w *= (float)vid.maxwarpheight / h; + } + + vrect.x = 0; + vrect.y = 0; + vrect.width = (int)w; + vrect.height = (int)h; + + R_ViewChanged (&vrect, + (int)((float)sb_lines * (h/(float)vid.height)), + vid.aspect * (h / w) * + ((float)vid.width / (float)vid.height)); + } + } + else + { + vrect.x = 0; + vrect.y = 0; + vrect.width = vid.width; + vrect.height = vid.height; + + R_ViewChanged (&vrect, sb_lines, vid.aspect); + } + + r_viewchanged = false; + } + +// start off with just the four screen edge clip planes + R_TransformFrustum (); + +// save base values + VectorCopy (vpn, base_vpn); + VectorCopy (vright, base_vright); + VectorCopy (vup, base_vup); + VectorCopy (modelorg, base_modelorg); + + R_SetSkyFrame (); + +// VerifyFrustumIndexes("bef"); + R_SetUpFrustumIndexes (); +// VerifyFrustumIndexes("aft"); + + r_cache_thrash = false; + +// clear frame counts + c_faceclip = 0; + d_spanpixcount = 0; + r_polycount = 0; + r_drawnpolycount = 0; + r_wholepolycount = 0; + r_amodels_drawn = 0; + r_outofsurfaces = 0; + r_outofedges = 0; + + D_SetupFrame (); +} + diff --git a/project/jni/application/quake/source/r_part.c b/project/jni/application/quake/source/r_part.c new file mode 100644 index 000000000..89b8633a3 --- /dev/null +++ b/project/jni/application/quake/source/r_part.c @@ -0,0 +1,1498 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "quakedef.h" +#include "r_local.h" + +#define MAX_PARTICLES 2048 // default max # of particles at one + // time +//Dan East: Reduced from 512 to 0 +#define ABSOLUTE_MIN_PARTICLES 0 // no fewer than this no matter what's + // on the command line + +int ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61}; +int ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66}; +int ramp3[8] = {0x6d, 0x6b, 6, 5, 4, 3}; + +particle_t *active_particles, *free_particles; + +particle_t *particles; + +int r_numparticles; +int r_allocatedparticles; + +vec3_t r_pright, r_pup, r_ppn; + +#define NUMVERTEXNORMALS 162 +extern float r_avertexnormals[NUMVERTEXNORMALS][3]; + +#ifdef USEFPM +particle_FPM_t *active_particlesFPM, *free_particlesFPM; +particle_FPM_t *particlesFPM; +vec3_FPM_t r_prightFPM, r_pupFPM, r_ppnFPM; +extern fixedpoint_t r_avertexnormalsFPM[NUMVERTEXNORMALS][3]; +#endif //USEFPM + + +/* +=============== +R_InitParticles +=============== +*/ +void R_InitParticles (void) +{ + int i; + + i = COM_CheckParm ("-particles"); + + if (i) + { + r_numparticles = (int)(Q_atoi(com_argv[i+1])); + if (r_numparticles < ABSOLUTE_MIN_PARTICLES) + r_numparticles = ABSOLUTE_MIN_PARTICLES; + } + else + { + r_numparticles = (int)r_maxparticles.value;//MAX_PARTICLES; + } + + r_allocatedparticles=r_numparticles; + + particles = (particle_t *) + Hunk_AllocName (r_numparticles * sizeof(particle_t), "particles"); +} + +#ifdef USEFPM +void R_InitParticlesFPM (void) +{ + int i; + + i = COM_CheckParm ("-particles"); + + if (i) + { + r_numparticles = (int)(Q_atoi(com_argv[i+1])); + if (r_numparticles < ABSOLUTE_MIN_PARTICLES) + r_numparticles = ABSOLUTE_MIN_PARTICLES; + } + else + { + r_numparticles = MAX_PARTICLES; + } + + particlesFPM = (particle_FPM_t *) + Hunk_AllocName (r_numparticles * sizeof(particle_FPM_t), "particles"); + + //Dan: TODO: prebuild this table and load it in r_alias, instead of converting it + //from the existing float table. + for (i=0; iorigin[0]; + org[1] = ent->origin[1]; + org[2] = ent->origin[2]; + for (i=-16 ; i<16 ; i+=8) + for (j=-16 ; j<16 ; j+=8) + for (k=0 ; k<32 ; k+=8) + { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = cl.time + 0.2 + (rand()&7) * 0.02; + p->color = 150 + rand()%6; + p->type = pt_slowgrav; + + dir[0] = j*8; + dir[1] = i*8; + dir[2] = k*8; + + p->org[0] = org[0] + i + (rand()&3); + p->org[1] = org[1] + j + (rand()&3); + p->org[2] = org[2] + k + (rand()&3); + + VectorNormalize (dir); + vel = 50 + (rand()&63); + VectorScale (dir, vel, p->vel); + } +} +#endif + + +/* +=============== +R_EntityParticles +=============== +*/ + +vec3_t avelocities[NUMVERTEXNORMALS]; +#ifdef USEFPM +vec3_FPM_t avelocitiesFPM[NUMVERTEXNORMALS]; +fixedpoint_t beamlengthFPM = FPM_FROMLONGC(16); +#endif //USEFPM +float beamlength = 16; +vec3_t avelocity = {23, 7, 3}; +float partstep = (float)0.01; +float timescale = (float)0.01; + +void R_EntityParticles (entity_t *ent) +{ + int count; + int i; + particle_t *p; + float angle; + float sr, sp, sy, cr, cp, cy; + vec3_t forward; + float dist; + + dist = 64; + count = 50; + +if (!avelocities[0][0]) +{ +for (i=0 ; inext; + p->next = active_particles; + active_particles = p; + + p->die = (float)(cl.time + 0.01); + p->color = 0x6f; + p->type = pt_explode; + + p->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength; + p->org[1] = ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength; + p->org[2] = ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength; + } +} + +#ifdef USEFPM +void R_EntityParticlesFPM (entity_FPM_t *ent) +{ + int count; + int i; + particle_FPM_t *p; + fixedpoint_t angle; + fixedpoint_t sr, sp, sy, cr, cp, cy; + vec3_FPM_t forward; + fixedpoint_t dist; + + dist = FPM_FROMLONG(64); + count = 50; + + if (!avelocitiesFPM[0][0]) + for (i=0 ; i fixedpoint conversions here. We're lucky if we + //break even instruction-wise with the original all-float routine. + angle = FPM_MUL(FPM_FROMFLOAT(clFPM.time), avelocitiesFPM[i][0]); + sy = FPM_SIN(angle); + cy = FPM_COS(angle); + angle = FPM_MUL(FPM_FROMFLOAT(clFPM.time), avelocitiesFPM[i][1]); + sp = FPM_SIN(angle); + cp = FPM_COS(angle); + angle = FPM_MUL(FPM_FROMFLOAT(clFPM.time), avelocitiesFPM[i][2]); + sr = FPM_SIN(angle); + cr = FPM_COS(angle); + + forward[0] = FPM_MUL(cp,cy); + forward[1] = FPM_MUL(cp,sy); + forward[2] = -sp; + + if (!free_particlesFPM) + return; + p = free_particlesFPM; + free_particlesFPM = p->next; + p->next = active_particlesFPM; + active_particlesFPM = p; + + p->die = FPM_ADD(FPM_FROMFLOAT(clFPM.time), FPM_FROMFLOAT(0.01)); + p->color = 0x6f; + p->type = pt_explode; + + p->org[0] = FPM_ADD3(ent->origin[0], FPM_MUL(r_avertexnormalsFPM[i][0],dist), FPM_MUL(forward[0],beamlengthFPM)); + p->org[1] = FPM_ADD3(ent->origin[1], FPM_MUL(r_avertexnormalsFPM[i][1],dist), FPM_MUL(forward[1],beamlengthFPM)); + p->org[2] = FPM_ADD3(ent->origin[2], FPM_MUL(r_avertexnormalsFPM[i][2],dist), FPM_MUL(forward[2],beamlengthFPM)); + } +} +#endif //USEFPM + +/* +=============== +R_ClearParticles +=============== +*/ +void R_ClearParticles (void) +{ + int i; + + free_particles = &particles[0]; + active_particles = NULL; + + for (i=0 ;inext; + p->next = active_particles; + active_particles = p; + + p->die = 99999; + p->color = (float)((-c)&15); + p->type = pt_static; + VectorCopy (vec3_origin, p->vel); + VectorCopy (org, p->org); + } + + fclose(f); + Con_Printf ("%i points read\n", c); +} + +#ifdef USEFPM +void R_ReadPointFile_fFPM (void) +{ + FILE *f; + vec3_FPM_t org; + int r; + int c; + particle_FPM_t *p; + char name[MAX_OSPATH]; + + sprintf (name,"maps\\%s.pts", sv.name); + + COM_FOpenFile (name, &f); + if (!f) + { + Con_Printf ("couldn't open %s\n", name); + return; + } + + Con_Printf ("Reading %s...\n", name); + c = 0; + for ( ;; ) + { + r = fscanf (f,"%f %f %f\n", &org[0], &org[1], &org[2]); + if (r != 3) + break; + c++; + + if (!free_particlesFPM) + { + Con_Printf ("Not enough free particles\n"); + break; + } + p = free_particlesFPM; + free_particlesFPM = p->next; + p->next = active_particlesFPM; + active_particlesFPM = p; + + p->die = FPM_FROMLONG(99999); + p->color = ((-c)&15); + p->type = pt_static; + VectorCopy (vec3_originFPM, p->vel); + + //Dan: Here we convert the vector from the floats stored in the wad + p->org[0]=FPM_FROMFLOAT(org[0]); + p->org[1]=FPM_FROMFLOAT(org[1]); + p->org[2]=FPM_FROMFLOAT(org[2]); + //VectorCopy (org, p->org); + } + + fclose (f); + Con_Printf ("%i points read\n", c); +} +#endif //USEFPM + +/* +=============== +R_ParseParticleEffect + +Parse an effect out of the server message +=============== +*/ +void R_ParseParticleEffect (void) +{ + vec3_t org, dir; + int i, count, msgcount, color; + + for (i=0 ; i<3 ; i++) + org[i] = MSG_ReadCoord (); + for (i=0 ; i<3 ; i++) + dir[i] = (float)(MSG_ReadChar () * (1.0/16)); + msgcount = MSG_ReadByte (); + color = MSG_ReadByte (); + +if (msgcount == 255) + count = 1024; +else + count = msgcount; + + R_RunParticleEffect (org, dir, color, count); +} + +#ifdef USEFPM +void R_ParseParticleEffectFPM (void) +{ + vec3_FPM_t org, dir; + int i, count, msgcount, color; + + for (i=0 ; i<3 ; i++) + org[i] = FPM_FROMFLOAT(MSG_ReadCoord ()); + for (i=0 ; i<3 ; i++) + dir[i] = FPM_MUL(FPM_FROMLONG(MSG_ReadChar ()), FPM_FROMFLOAT(1.0/16)); + msgcount = MSG_ReadByte (); + color = MSG_ReadByte (); + +if (msgcount == 255) + count = 1024; +else + count = msgcount; + + R_RunParticleEffectFPM (org, dir, color, count); +} +#endif //USEFPM + +/* +=============== +R_ParticleExplosion + +=============== +*/ +void R_ParticleExplosion (vec3_t org) +{ + int i, j; + particle_t *p; + + for (i=0 ; i<1024 ; i++) + { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = (float)(cl.time + 5); + p->color = (float)ramp1[0]; + p->ramp = (float)(rand()&3); + if (i & 1) + { + p->type = pt_explode; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (float)((rand()%512)-256); + } + } + else + { + p->type = pt_explode2; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (float)((rand()%512)-256); + } + } + } +} + +#ifdef USEFPM +void R_ParticleExplosionFPM (vec3_FPM_t org) +{ + int i, j; + particle_FPM_t *p; + + for (i=0 ; i<1024 ; i++) + { + if (!free_particlesFPM) + return; + p = free_particlesFPM; + free_particlesFPM = p->next; + p->next = active_particlesFPM; + active_particlesFPM = p; + + p->die = FPM_ADD(FPM_FROMFLOAT(clFPM.time), FPM_FROMLONG(5)); + p->color = ramp1[0]; + p->ramp = FPM_FROMLONG(rand()&3); + if (i & 1) + { + p->type = pt_explode; + for (j=0 ; j<3 ; j++) + { + p->org[j] = FPM_ADD(org[j], FPM_FROMLONG((rand()%32)-16)); + p->vel[j] = FPM_FROMLONG((rand()%512)-256); + } + } + else + { + p->type = pt_explode2; + for (j=0 ; j<3 ; j++) + { + p->org[j] = FPM_ADD(org[j], FPM_FROMLONG((rand()%32)-16)); + p->vel[j] = FPM_FROMLONG((rand()%512)-256); + } + } + } +} +#endif //USEFPM + +/* +=============== +R_ParticleExplosion2 + +=============== +*/ +void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength) +{ + int i, j; + particle_t *p; + int colorMod = 0; + + for (i=0; i<512; i++) + { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = (float)(cl.time + 0.3); + p->color = (float)(colorStart + (colorMod % colorLength)); + colorMod++; + + p->type = pt_blob; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (float)((rand()%512)-256); + } + } +} + +#ifdef USEFPM +void R_ParticleExplosion2FPM (vec3_FPM_t org, int colorStart, int colorLength) +{ + int i, j; + particle_FPM_t *p; + int colorMod = 0; + + for (i=0; i<512; i++) + { + if (!free_particlesFPM) + return; + p = free_particlesFPM; + free_particlesFPM = p->next; + p->next = active_particlesFPM; + active_particlesFPM = p; + + p->die = FPM_ADD(FPM_FROMFLOAT(clFPM.time), FPM_FROMFLOAT(0.3)); + p->color = (colorStart + (colorMod % colorLength)); + colorMod++; + + p->type = pt_blob; + for (j=0 ; j<3 ; j++) + { + p->org[j] = FPM_ADD(org[j], FPM_FROMLONG((rand()%32)-16)); + p->vel[j] = FPM_FROMLONG((rand()%512)-256); + } + } +} +#endif //USEFPM + +/* +=============== +R_BlobExplosion + +=============== +*/ +void R_BlobExplosion (vec3_t org) +{ + int i, j; + particle_t *p; + + for (i=0 ; i<1024 ; i++) + { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = (float)(cl.time + 1 + (rand()&8)*0.05); + + if (i & 1) + { + p->type = pt_blob; + p->color = (float)(66 + rand()%6); + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (float)((rand()%512)-256); + } + } + else + { + p->type = pt_blob2; + p->color = (float)(150 + rand()%6); + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (float)((rand()%512)-256); + } + } + } +} + +#ifdef USEFPM +void R_BlobExplosionFPM (vec3_FPM_t org) +{ + int i, j; + particle_FPM_t *p; + + for (i=0 ; i<1024 ; i++) + { + if (!free_particlesFPM) + return; + p = free_particlesFPM; + free_particlesFPM = p->next; + p->next = active_particlesFPM; + active_particlesFPM = p; + + p->die = FPM_ADD3(FPM_FROMFLOAT(clFPM.time), 1, FPM_MUL(FPM_FROMLONG(rand()&8),FPM_FROMFLOAT(0.05))); + + if (i & 1) + { + p->type = pt_blob; + p->color = (66 + rand()%6); + for (j=0 ; j<3 ; j++) + { + p->org[j] = FPM_ADD(org[j], FPM_FROMLONG((rand()%32)-16)); + p->vel[j] = FPM_FROMLONG((rand()%512)-256); + } + } + else + { + p->type = pt_blob2; + p->color = (150 + rand()%6); + for (j=0 ; j<3 ; j++) + { + p->org[j] = FPM_ADD(org[j], FPM_FROMLONG((rand()%32)-16)); + p->vel[j] = FPM_FROMLONG((rand()%512)-256); + } + } + } +} +#endif //USEFPM + +/* +=============== +R_RunParticleEffect + +=============== +*/ +void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count) +{ + int i, j; + particle_t *p; + + for (i=0 ; inext; + p->next = active_particles; + active_particles = p; + + if (count == 1024) + { // rocket explosion + p->die = (float)(cl.time + 5); + p->color = (float)ramp1[0]; + p->ramp = (float)(rand()&3); + if (i & 1) + { + p->type = pt_explode; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (float)((rand()%512)-256); + } + } + else + { + p->type = pt_explode2; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()%32)-16); + p->vel[j] = (float)((rand()%512)-256); + } + } + } + else + { + p->die = (float)(cl.time + 0.1*(rand()%5)); + p->color = (float)((color&~7) + (rand()&7)); + p->type = pt_slowgrav; + for (j=0 ; j<3 ; j++) + { + p->org[j] = org[j] + ((rand()&15)-8); + p->vel[j] = dir[j]*15;// + (rand()%300)-150; + } + } + } +} + +#ifdef USEFPM +void R_RunParticleEffectFPM (vec3_FPM_t org, vec3_FPM_t dir, int color, int count) +{ + int i, j; + particle_FPM_t *p; + + for (i=0 ; inext; + p->next = active_particlesFPM; + active_particlesFPM = p; + + if (count == 1024) + { // rocket explosion + p->die = FPM_ADD(FPM_FROMFLOAT(clFPM.time), FPM_FROMLONG(5)); + p->color = ramp1[0]; + p->ramp = FPM_FROMLONG(rand()&3); + if (i & 1) + { + p->type = pt_explode; + for (j=0 ; j<3 ; j++) + { + p->org[j] = FPM_ADD(org[j], FPM_FROMLONG((rand()%32)-16)); + p->vel[j] = FPM_FROMLONG((rand()%512)-256); + } + } + else + { + p->type = pt_explode2; + for (j=0 ; j<3 ; j++) + { + p->org[j] = FPM_ADD(org[j], FPM_FROMLONG((rand()%32)-16)); + p->vel[j] = FPM_FROMLONG((rand()%512)-256); + } + } + } + else + { + p->die = FPM_ADD(FPM_FROMFLOAT(clFPM.time), FPM_MUL(FPM_FROMFLOAT(0.1),FPM_FROMLONG(rand()%5))); + p->color = ((color&~7) + (rand()&7)); + p->type = pt_slowgrav; + for (j=0 ; j<3 ; j++) + { + p->org[j] = FPM_ADD(org[j], FPM_FROMLONG((rand()&15)-8)); + p->vel[j] = FPM_MUL(dir[j],FPM_FROMLONG(15));// + (rand()%300)-150; + } + } + } +} +#endif //USEFPM + +/* +=============== +R_LavaSplash + +=============== +*/ +void R_LavaSplash (vec3_t org) +{ + int i, j, k; + particle_t *p; + float vel; + vec3_t dir; + + for (i=-16 ; i<16 ; i++) + for (j=-16 ; j<16 ; j++) + for (k=0 ; k<1 ; k++) + { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = (float)(cl.time + 2 + (rand()&31) * 0.02); + p->color = (float)(224 + (rand()&7)); + p->type = pt_slowgrav; + + dir[0] = (float)(j*8 + (rand()&7)); + dir[1] = (float)(i*8 + (rand()&7)); + dir[2] = 256; + + p->org[0] = org[0] + dir[0]; + p->org[1] = org[1] + dir[1]; + p->org[2] = org[2] + (rand()&63); + + VectorNormalize (dir); + vel = (float)(50 + (rand()&63)); + VectorScale (dir, vel, p->vel); + } +} + +#ifdef USEFPM +void R_LavaSplashFPM (vec3_FPM_t org) +{ + int i, j, k; + particle_FPM_t *p; + fixedpoint_t vel; + vec3_FPM_t dir; + + for (i=-16 ; i<16 ; i++) + for (j=-16 ; j<16 ; j++) + for (k=0 ; k<1 ; k++) + { + if (!free_particlesFPM) + return; + p = free_particlesFPM; + free_particlesFPM = p->next; + p->next = active_particlesFPM; + active_particlesFPM = p; + + p->die = FPM_ADD3(FPM_FROMFLOAT(clFPM.time), FPM_FROMLONG(2), FPM_MUL(FPM_FROMLONG(rand()&31), FPM_FROMFLOAT(0.02))); + p->color = (224 + (rand()&7)); + p->type = pt_slowgrav; + + dir[0] = FPM_FROMLONG(j*8 + (rand()&7)); + dir[1] = FPM_FROMLONG(i*8 + (rand()&7)); + dir[2] = FPM_FROMLONG(256); + + p->org[0] = FPM_ADD(org[0], dir[0]); + p->org[1] = FPM_ADD(org[1], dir[1]); + p->org[2] = FPM_ADD(org[2], FPM_FROMLONG(rand()&63)); + + VectorNormalizeFPM (dir); + vel = FPM_FROMLONG(50 + (rand()&63)); + VectorScaleFPM (dir, vel, p->vel); + } +} +#endif //USEFPM + +/* +=============== +R_TeleportSplash + +=============== +*/ +void R_TeleportSplash (vec3_t org) +{ + int i, j, k; + particle_t *p; + float vel; + vec3_t dir; + + for (i=-16 ; i<16 ; i+=4) + for (j=-16 ; j<16 ; j+=4) + for (k=-24 ; k<32 ; k+=4) + { + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + p->die = (float)(cl.time + 0.2 + (rand()&7) * 0.02); + p->color = (float)(7 + (rand()&7)); + p->type = pt_slowgrav; + + dir[0] = (float)j*8; + dir[1] = (float)i*8; + dir[2] = (float)k*8; + + p->org[0] = org[0] + i + (rand()&3); + p->org[1] = org[1] + j + (rand()&3); + p->org[2] = org[2] + k + (rand()&3); + + VectorNormalize (dir); + vel = (float)(50 + (rand()&63)); + VectorScale (dir, vel, p->vel); + } +} + +#ifdef USEFPM +void R_TeleportSplashFPM (vec3_FPM_t org) +{ + int i, j, k; + particle_FPM_t *p; + fixedpoint_t vel; + vec3_FPM_t dir; + + for (i=-16 ; i<16 ; i+=4) + for (j=-16 ; j<16 ; j+=4) + for (k=-24 ; k<32 ; k+=4) + { + if (!free_particlesFPM) + return; + p = free_particlesFPM; + free_particlesFPM = p->next; + p->next = active_particlesFPM; + active_particlesFPM = p; + + p->die = FPM_ADD3(FPM_FROMFLOAT(clFPM.time), FPM_FROMFLOAT(0.2), FPM_MUL(FPM_FROMLONG(rand()&7), FPM_FROMFLOAT(0.02))); + p->color = (7 + (rand()&7)); + p->type = pt_slowgrav; + + dir[0] = FPM_FROMLONG(j*8); + dir[1] = FPM_FROMLONG(i*8); + dir[2] = FPM_FROMLONG(k*8); + + p->org[0] = FPM_ADD(org[0], FPM_FROMLONG(i + (rand()&3))); + p->org[1] = FPM_ADD(org[1], FPM_FROMLONG(j + (rand()&3))); + p->org[2] = FPM_ADD(org[2], FPM_FROMLONG(k + (rand()&3))); + + VectorNormalizeFPM (dir); + vel = FPM_FROMLONG(50 + (rand()&63)); + VectorScaleFPM(dir, vel, p->vel); + } +} +#endif //USEFPM + +void R_RocketTrail (vec3_t start, vec3_t end, int type) +{ + vec3_t vec; + float len; + int j; + particle_t *p; + int dec; + static int tracercount; + + VectorSubtract (end, start, vec); + len = VectorNormalize (vec); + if (type < 128) + dec = 3; + else + { + dec = 1; + type -= 128; + } + + while (len > 0) + { + len -= dec; + + if (!free_particles) + return; + p = free_particles; + free_particles = p->next; + p->next = active_particles; + active_particles = p; + + VectorCopy (vec3_origin, p->vel); + p->die = (float)(cl.time + 2); + + switch (type) + { + case 0: // rocket trail + p->ramp = (float)((rand()&3)); + p->color = (float)(ramp3[(int)p->ramp]); + p->type = pt_fire; + for (j=0 ; j<3 ; j++) + p->org[j] = start[j] + ((rand()%6)-3); + break; + + case 1: // smoke smoke + p->ramp = (float)((rand()&3) + 2); + p->color = (float)(ramp3[(int)p->ramp]); + p->type = pt_fire; + for (j=0 ; j<3 ; j++) + p->org[j] = start[j] + ((rand()%6)-3); + break; + + case 2: // blood + p->type = pt_grav; + p->color = (float)(67 + (rand()&3)); + for (j=0 ; j<3 ; j++) + p->org[j] = start[j] + ((rand()%6)-3); + break; + + case 3: + case 5: // tracer + p->die = (float)(cl.time + 0.5); + p->type = pt_static; + if (type == 3) + p->color = (float)(52 + ((tracercount&4)<<1)); + else + p->color = (float)(230 + ((tracercount&4)<<1)); + + tracercount++; + + VectorCopy (start, p->org); + if (tracercount & 1) + { + p->vel[0] = 30*vec[1]; + p->vel[1] = 30*-vec[0]; + } + else + { + p->vel[0] = 30*-vec[1]; + p->vel[1] = 30*vec[0]; + } + break; + + case 4: // slight blood + p->type = pt_grav; + p->color = (float)(67 + (rand()&3)); + for (j=0 ; j<3 ; j++) + p->org[j] = start[j] + ((rand()%6)-3); + len -= 3; + break; + + case 6: // voor trail + p->color = (float)(9*16 + 8 + (rand()&3)); + p->type = pt_static; + p->die = (float)(cl.time + 0.3); + for (j=0 ; j<3 ; j++) + p->org[j] = start[j] + ((rand()&15)-8); + break; + } + + + VectorAdd (start, vec, start); + } +} + +#ifdef USEFPM +void R_RocketTrailFPM (vec3_FPM_t start, vec3_FPM_t end, int type) +{ + vec3_FPM_t vec; + fixedpoint_t len; + int j; + particle_FPM_t *p; + //Dan: changed dec from int to fixedpoint_t, so it is the same type as len + fixedpoint_t dec; + static int tracercount; + + VectorSubtractFPM (end, start, vec); + len = VectorNormalizeFPM (vec); + if (type < FPM_FROMLONG(128)) + dec = FPM_FROMLONG(3); + else + { + dec = FPM_FROMLONG(1); + type -= 128; + } + + while (len > 0) + { + len=FPM_SUB(len, dec); + + if (!free_particlesFPM) + return; + p = free_particlesFPM; + free_particlesFPM = p->next; + p->next = active_particlesFPM; + active_particlesFPM = p; + + VectorCopy(vec3_originFPM, p->vel); + p->die = FPM_ADD(FPM_FROMFLOAT(clFPM.time), 2); + + switch (type) + { + case 0: // rocket trail + p->ramp = FPM_FROMLONG((rand()&3)); + p->color = (ramp3[FPM_TOLONG(p->ramp)]); + p->type = pt_fire; + for (j=0 ; j<3 ; j++) + p->org[j] = FPM_ADD(start[j], FPM_FROMLONG((rand()%6)-3)); + break; + + case 1: // smoke smoke + p->ramp = FPM_FROMLONG((rand()&3) + 2); + p->color = (ramp3[FPM_TOLONG(p->ramp)]); + p->type = pt_fire; + for (j=0 ; j<3 ; j++) + p->org[j] = FPM_ADD(start[j], FPM_FROMLONG((rand()%6)-3)); + break; + + case 2: // blood + p->type = pt_grav; + p->color = (67 + (rand()&3)); + for (j=0 ; j<3 ; j++) + p->org[j] = FPM_ADD(start[j], FPM_FROMLONG((rand()%6)-3)); + break; + + case 3: + case 5: // tracer + p->die = FPM_ADD(FPM_FROMFLOAT(clFPM.time), FPM_FROMFLOAT(0.5)); + p->type = pt_static; + if (type == 3) + p->color = (52 + ((tracercount&4)<<1)); + else + p->color = (230 + ((tracercount&4)<<1)); + + tracercount++; + + VectorCopy (start, p->org); + if (tracercount & 1) + { + p->vel[0] = FPM_MUL(30,vec[1]); + p->vel[1] = FPM_MUL(30,-vec[0]); + } + else + { + p->vel[0] = FPM_MUL(30,-vec[1]); + p->vel[1] = FPM_MUL(30,vec[0]); + } + break; + + case 4: // slight blood + p->type = pt_grav; + p->color = (67 + (rand()&3)); + for (j=0 ; j<3 ; j++) + p->org[j] = FPM_ADD(start[j], FPM_FROMLONG((rand()%6)-3)); + len -= 3; + break; + + case 6: // voor trail + p->color = (9*16 + 8 + (rand()&3)); + p->type = pt_static; + p->die = FPM_ADD(FPM_FROMFLOAT(clFPM.time), FPM_FROMFLOAT(0.3)); + for (j=0 ; j<3 ; j++) + p->org[j] = FPM_ADD(start[j], FPM_FROMLONG((rand()&15)-8)); + break; + } + + + VectorAddFPM (start, vec, start); + } +} +#endif //USEFPM + +/* +=============== +R_DrawParticles +=============== +*/ +extern cvar_t sv_gravity; + +void R_DrawParticles (void) +{ + particle_t *p, *kill; + float grav; + int i; + float time2, time3; + float time1; + float dvel; + float frametime; + +#ifdef GLQUAKE + vec3_t up, right; + float scale; + + GL_Bind(particletexture); + glEnable (GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBegin (GL_TRIANGLES); + + VectorScale (vup, 1.5, up); + VectorScale (vright, 1.5, right); +#else + D_StartParticles (); + + VectorScale (vright, xscaleshrink, r_pright); + VectorScale (vup, yscaleshrink, r_pup); + VectorCopy (vpn, r_ppn); +#endif + frametime = (float)(cl.time - cl.oldtime); + time3 = frametime * 15; + time2 = frametime * 10; // 15; + time1 = frametime * 5; + grav = (float)(frametime * sv_gravity.value * 0.05); + dvel = 4*frametime; + + for ( ;; ) + { + kill = active_particles; + if (kill && kill->die < cl.time) + { + active_particles = kill->next; + kill->next = free_particles; + free_particles = kill; + continue; + } + break; + } + + for (p=active_particles ; p ; p=p->next) + { + for ( ;; ) + { + kill = p->next; + if (kill && kill->die < cl.time) + { + p->next = kill->next; + kill->next = free_particles; + free_particles = kill; + continue; + } + break; + } + +#ifdef GLQUAKE + // hack a scale up to keep particles from disapearing + scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1] + + (p->org[2] - r_origin[2])*vpn[2]; + if (scale < 20) + scale = 1; + else + scale = 1 + scale * 0.004; + glColor3ubv ((byte *)&d_8to24table[(int)p->color]); + glTexCoord2f (0,0); + glVertex3fv (p->org); + glTexCoord2f (1,0); + glVertex3f (p->org[0] + up[0]*scale, p->org[1] + up[1]*scale, p->org[2] + up[2]*scale); + glTexCoord2f (0,1); + glVertex3f (p->org[0] + right[0]*scale, p->org[1] + right[1]*scale, p->org[2] + right[2]*scale); +#else + D_DrawParticle (p); +#endif + p->org[0] += p->vel[0]*frametime; + p->org[1] += p->vel[1]*frametime; + p->org[2] += p->vel[2]*frametime; + + switch (p->type) + { + case pt_static: + break; + case pt_fire: + p->ramp += time1; + if (p->ramp >= 6) + p->die = -1; + else + p->color = (float)(ramp3[(int)p->ramp]); + p->vel[2] += grav; + break; + + case pt_explode: + p->ramp += time2; + if (p->ramp >=8) + p->die = -1; + else + p->color = (float)(ramp1[(int)p->ramp]); + for (i=0 ; i<3 ; i++) + p->vel[i] += p->vel[i]*dvel; + p->vel[2] -= grav; + break; + + case pt_explode2: + p->ramp += time3; + if (p->ramp >=8) + p->die = -1; + else + p->color = (float)(ramp2[(int)p->ramp]); + for (i=0 ; i<3 ; i++) + p->vel[i] -= p->vel[i]*frametime; + p->vel[2] -= grav; + break; + + case pt_blob: + for (i=0 ; i<3 ; i++) + p->vel[i] += p->vel[i]*dvel; + p->vel[2] -= grav; + break; + + case pt_blob2: + for (i=0 ; i<2 ; i++) + p->vel[i] -= p->vel[i]*dvel; + p->vel[2] -= grav; + break; + + case pt_grav: +#ifdef QUAKE2 + p->vel[2] -= grav * 20; + break; +#endif + case pt_slowgrav: + p->vel[2] -= grav; + break; + } + } + +#ifdef GLQUAKE + glEnd (); + glDisable (GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +#else + D_EndParticles (); +#endif +} + +#ifdef USEFPM +void R_DrawParticlesFPM (void) +{ + particle_FPM_t *p, *kill; + fixedpoint_t grav; + int i; + fixedpoint_t time1, time2, time3; + fixedpoint_t dvel; + fixedpoint_t frametime; + //Dan: var used for one-time fixedpoint conversion + fixedpoint_t cltime=FPM_FROMFLOAT(clFPM.time); + +#ifdef GLQUAKE + //Dan: not converted, unused by Pocket PC + vec3_t up, right; + float scale; + + GL_Bind(particletexture); + glEnable (GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glBegin (GL_TRIANGLES); + + VectorScale (vup, 1.5, up); + VectorScale (vright, 1.5, right); +#else + //Dan: Empty function + //D_StartParticlesFPM (); + + VectorScaleFPM (vrightFPM, xscaleshrinkFPM, r_prightFPM); + VectorScaleFPM (vupFPM, yscaleshrinkFPM, r_pupFPM); + VectorCopy (vpn, r_ppn); +#endif + frametime = FPM_SUB(cltime, FPM_FROMFLOAT(clFPM.oldtime)); + time3 = FPM_MUL(frametime, FPM_FROMLONG(15)); + time2 = FPM_MUL(frametime, FPM_FROMLONG(10)); // 15; + time1 = FPM_MUL(frametime, FPM_FROMLONG(5)); + grav = FPM_MUL(FPM_MUL(frametime, FPM_FROMFLOAT(sv_gravity.value)), FPM_FROMFLOAT(0.05)); + dvel = FPM_MUL(FPM_FROMLONGC(4), frametime); + + for ( ;; ) + { + kill = active_particlesFPM; + if (kill && kill->die < cltime) + { + active_particlesFPM = kill->next; + kill->next = free_particlesFPM; + free_particlesFPM = kill; + continue; + } + break; + } + + for (p=active_particlesFPM ; p ; p=p->next) + { + for ( ;; ) + { + kill = p->next; + if (kill && kill->die < cltime) + { + p->next = kill->next; + kill->next = free_particlesFPM; + free_particlesFPM = kill; + continue; + } + break; + } + +#ifdef GLQUAKE + // hack a scale up to keep particles from disapearing + scale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1] + + (p->org[2] - r_origin[2])*vpn[2]; + if (scale < 20) + scale = 1; + else + scale = 1 + scale * 0.004; + glColor3ubv ((byte *)&d_8to24table[(int)p->color]); + glTexCoord2f (0,0); + glVertex3fv (p->org); + glTexCoord2f (1,0); + glVertex3f (p->org[0] + up[0]*scale, p->org[1] + up[1]*scale, p->org[2] + up[2]*scale); + glTexCoord2f (0,1); + glVertex3f (p->org[0] + right[0]*scale, p->org[1] + right[1]*scale, p->org[2] + right[2]*scale); +#else + D_DrawParticleFPM (p); +#endif + p->org[0] = FPM_ADD(p->org[0], FPM_MUL(p->vel[0],frametime)); + p->org[1] = FPM_ADD(p->org[1], FPM_MUL(p->vel[1],frametime)); + p->org[2] = FPM_ADD(p->org[2], FPM_MUL(p->vel[2],frametime)); + + switch (p->type) + { + case pt_static: + break; + case pt_fire: + p->ramp = FPM_ADD(p->ramp, time1); + if (p->ramp >= FPM_FROMLONGC(6)) + p->die = FPM_FROMLONGC(-1); + else + p->color = (ramp3[FPM_TOLONG(p->ramp)]); + p->vel[2] = FPM_ADD(p->vel[2], grav); + break; + + case pt_explode: + p->ramp = FPM_ADD(p->ramp, time2); + if (p->ramp >=FPM_FROMLONGC(8)) + p->die = FPM_FROMLONGC(-1); + else + p->color = (ramp1[FPM_TOLONG(p->ramp)]); + for (i=0 ; i<3 ; i++) + p->vel[i] = FPM_ADD(p->vel[i], FPM_MUL(p->vel[i], dvel)); + p->vel[2] = FPM_SUB(p->vel[2], grav); + break; + + case pt_explode2: + p->ramp = FPM_ADD(p->ramp, time3); + if (p->ramp >= FPM_FROMLONGC(8)) + p->die = FPM_FROMLONGC(-1); + else + p->color = (ramp2[FPM_TOLONG(p->ramp)]); + for (i=0 ; i<3 ; i++) + p->vel[i] = FPM_SUB(p->vel[i], FPM_MUL(p->vel[i],frametime)); + p->vel[2] = FPM_SUB(p->vel[2], grav); + break; + + case pt_blob: + for (i=0 ; i<3 ; i++) + p->vel[i] = FPM_ADD(p->vel[i], FPM_MUL(p->vel[i],dvel)); + p->vel[2] = FPM_SUB(p->vel[2], grav); + break; + + case pt_blob2: + for (i=0 ; i<2 ; i++) + p->vel[i] = FPM_SUB(p->vel[i], FPM_MUL(p->vel[i],dvel)); + p->vel[2] = FPM_SUB(p->vel[2], grav); + break; + + case pt_grav: +#ifdef QUAKE2 + p->vel[2] = FPM_SUB(p->vel[2], FPM_MUL(grav, 20)); + break; +#endif + case pt_slowgrav: + p->vel[2] = FPM_SUB(p->vel[2], grav); + break; + } + } + +#ifdef GLQUAKE + glEnd (); + glDisable (GL_BLEND); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +#else + //Dan: Empty function + //D_EndParticlesFPM (); +#endif +} +#endif //USEFPM diff --git a/project/jni/application/quake/source/r_shared.h b/project/jni/application/quake/source/r_shared.h new file mode 100644 index 000000000..577085d95 --- /dev/null +++ b/project/jni/application/quake/source/r_shared.h @@ -0,0 +1,215 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef GLQUAKE +// r_shared.h: general refresh-related stuff shared between the refresh and the +// driver + +// FIXME: clean up and move into d_iface.h + +#ifndef _R_SHARED_H_ +#define _R_SHARED_H_ + +#define MAXVERTS 16 // max points in a surface polygon +#define MAXWORKINGVERTS (MAXVERTS+4) // max points in an intermediate + // polygon (while processing) +// !!! if this is changed, it must be changed in d_ifacea.h too !!! +#define MAXHEIGHT 1024 +#define MAXWIDTH 1280 +#define MAXDIMENSION ((MAXHEIGHT > MAXWIDTH) ? MAXHEIGHT : MAXWIDTH) + +#define SIN_BUFFER_SIZE (MAXDIMENSION+CYCLE) + +#define INFINITE_DISTANCE 0x10000 // distance that's always guaranteed to + // be farther away than anything in + // the scene + +//=================================================================== + +extern void R_DrawLine (polyvert_t *polyvert0, polyvert_t *polyvert1); + +extern int cachewidth; +extern pixel_t *cacheblock; +extern int screenwidth; + +extern float pixelAspect; +extern fixedpoint_t pixelAspectFPM; + +extern int r_drawnpolycount; + +extern cvar_t r_clearcolor; + +extern int sintable[SIN_BUFFER_SIZE]; +extern int intsintable[SIN_BUFFER_SIZE]; + +extern vec3_t vup, base_vup; +extern vec3_FPM_t vupFPM, base_vupFPM; +extern vec3_t vpn, base_vpn; +extern vec3_FPM_t vpnFPM, base_vpnFPM; +extern vec3_t vright, base_vright; +extern vec3_FPM_t vrightFPM, base_vrightFPM; +extern entity_t *currententity; +extern entity_FPM_t *currententityFPM; + +#define NUMSTACKEDGES 2400 +#define MINEDGES 300 +#define NUMSTACKSURFACES 800 +#define MINSURFACES 100 +#define MAXSPANS 3000 +/* +#define NUMSTACKEDGES 2400 +#define MINEDGES NUMSTACKEDGES +#define NUMSTACKSURFACES 800 +#define MINSURFACES NUMSTACKSURFACES +#define MAXSPANS 3000 +*/ +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct espan_s +{ + int u, v, count; + struct espan_s *pnext; +} espan_t; + +// FIXME: compress, make a union if that will help +// insubmodel is only 1, flags is fewer than 32, spanstate could be a byte +typedef struct surf_s +{ + struct surf_s *next; // active surface stack in r_edge.c + struct surf_s *prev; // used in r_edge.c for active surf stack + struct espan_s *spans; // pointer to linked list of spans to draw + int key; // sorting key (BSP order) + int last_u; // set during tracing + int spanstate; // 0 = not in span + // 1 = in span + // -1 = in inverted span (end before + // start) + int flags; // currentface flags + void *data; // associated data like msurface_t + entity_t *entity; + float nearzi; // nearest 1/z on surface, for mipmapping + qboolean insubmodel; +#ifndef USE_PQ_OPT3 + float d_ziorigin, d_zistepu, d_zistepv; +#else + int d_ziorigin_fxp, d_zistepu_fxp, d_zistepv_fxp; +#endif + + int pad[2]; // to 64 bytes +} surf_t; + +typedef struct surf_FPM_s +{ + struct surf_FPM_s *next; // active surface stack in r_edge.c + struct surf_FPM_s *prev; // used in r_edge.c for active surf stack + struct espan_s *spans; // pointer to linked list of spans to draw + int key; // sorting key (BSP order) + int last_u; // set during tracing + int spanstate; // 0 = not in span + // 1 = in span + // -1 = in inverted span (end before + // start) + int flags; // currentface flags + void *data; // associated data like msurface_t + entity_FPM_t *entity; + fixedpoint_t nearzi; // nearest 1/z on surface, for mipmapping + qboolean insubmodel; + fixedpoint_t d_ziorigin, d_zistepu, d_zistepv; + + int pad[2]; // to 64 bytes +} surf_FPM_t; + +extern surf_t *surfaces, *surface_p, *surf_max; +extern surf_FPM_t *surfacesFPM, *surface_FPM_p, *surf_maxFPM; + +// surfaces are generated in back to front order by the bsp, so if a surf +// pointer is greater than another one, it should be drawn in front +// surfaces[1] is the background, and is used as the active surface stack. +// surfaces[0] is a dummy, because index 0 is used to indicate no surface +// attached to an edge_t + +//=================================================================== + +extern vec3_t sxformaxis[4]; // s axis transformed into viewspace +extern vec3_t txformaxis[4]; // t axis transformed into viewspac + +extern vec3_t modelorg, base_modelorg; +extern vec3_FPM_t modelorgFPM, base_modelorgFPM; + +extern float xcenter, ycenter; +extern fixedpoint_t xcenterFPM, ycenterFPM; +extern float xscale, yscale; +extern fixedpoint_t xscaleFPM, yscaleFPM; +extern float xscaleinv, yscaleinv; +extern fixedpoint_t xscaleinvFPM, yscaleinvFPM; +extern float xscaleshrink, yscaleshrink; +extern fixedpoint_t xscaleshrinkFPM, yscaleshrinkFPM; + +extern int d_lightstylevalue[256]; // 8.8 frac of base light value + +extern void TransformVector (vec3_t in, vec3_t out); +#ifdef USE_PQ_OPT +//JB: Optimization +extern void FPTransformVector (fpvec3 in, fpvec3 out); +#endif +extern void TransformVectorFPM (vec3_FPM_t in, vec3_FPM_t out); +extern void SetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv, + fixed8_t endvertu, fixed8_t endvertv); + +extern int r_skymade; +extern void R_MakeSky (void); + +extern int ubasestep, errorterm, erroradjustup, erroradjustdown; + +// flags in finalvert_t.flags +#define ALIAS_LEFT_CLIP 0x0001 +#define ALIAS_TOP_CLIP 0x0002 +#define ALIAS_RIGHT_CLIP 0x0004 +#define ALIAS_BOTTOM_CLIP 0x0008 +#define ALIAS_Z_CLIP 0x0010 +// !!! if this is changed, it must be changed in d_ifacea.h too !!! +#define ALIAS_ONSEAM 0x0020 // also defined in modelgen.h; + // must be kept in sync +#define ALIAS_XY_CLIP_MASK 0x000F + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct edge_s +{ + fixed16_t u; + fixed16_t u_step; + struct edge_s *prev, *next; + unsigned short surfs[2]; + struct edge_s *nextremove; + float nearzi; + medge_t *owner; +} edge_t; + +typedef struct edge_FPM_s +{ + fixed16_t u; + fixed16_t u_step; + struct edge_FPM_s *prev, *next; + unsigned short surfs[2]; + struct edge_FPM_s *nextremove; + fixedpoint_t nearzi; + medge_t *owner; +} edge_FPM_t; + +#endif // _R_SHARED_H_ + +#endif // GLQUAKE diff --git a/project/jni/application/quake/source/r_sky.c b/project/jni/application/quake/source/r_sky.c new file mode 100644 index 000000000..efb47f3e4 --- /dev/null +++ b/project/jni/application/quake/source/r_sky.c @@ -0,0 +1,306 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_sky.c + +#include "quakedef.h" +#include "r_local.h" +#include "d_local.h" + + +int iskyspeed = 8; +int iskyspeed2 = 2; +float skyspeed, skyspeed2; + +float skytime; + +byte *r_skysource; + +int r_skymade; +int r_skydirect; // not used? + + +// TODO: clean up these routines + +byte bottomsky[128*131]; +byte bottommask[128*131]; +byte newsky[128*256]; // newsky and topsky both pack in here, 128 bytes + // of newsky on the left of each scan, 128 bytes + // of topsky on the right, because the low-level + // drawers need 256-byte scan widths + + +/* +============= +R_InitSky + +A sky texture is 256*128, with the right side being a masked overlay +============== +*/ +void R_InitSky (texture_t *mt) +{ + int i, j; + byte *src; + + src = (byte *)mt + mt->offsets[0]; + + for (i=0 ; i<128 ; i++) + { + for (j=0 ; j<128 ; j++) + { + newsky[(i*256) + j + 128] = src[i*256 + j + 128]; + } + } + + for (i=0 ; i<128 ; i++) + { + for (j=0 ; j<131 ; j++) + { + if (src[i*256 + (j & 0x7F)]) + { + bottomsky[(i*131) + j] = src[i*256 + (j & 0x7F)]; + bottommask[(i*131) + j] = 0; + } + else + { + bottomsky[(i*131) + j] = 0; + bottommask[(i*131) + j] = 0xff; + } + } + } + + r_skysource = newsky; +} + + +/* +================= +R_MakeSky +================= +*/ +void R_MakeSky (void) +{ + int x, y; + int ofs, baseofs; + int xshift, yshift; + unsigned *pnewsky; + static int xlast = -1, ylast = -1; + + xshift = (int)(skytime*skyspeed); + yshift = (int)(skytime*skyspeed); + + if ((xshift == xlast) && (yshift == ylast)) + return; + + xlast = xshift; + ylast = yshift; + + pnewsky = (unsigned *)&newsky[0]; + + for (y=0 ; ydist; + pclipnormal = pclipplane->normal; + +// calc dists + if (clip_current) + { + in = clip_verts[1][0]; + outstep = clip_verts[0][0]; + clip_current = 0; + } + else + { + in = clip_verts[0][0]; + outstep = clip_verts[1][0]; + clip_current = 1; + } + + instep = in; + for (i=0 ; i= 0) + { + Q_memcpy (outstep, instep, sizeof (vec5_t)); + outstep += sizeof (vec5_t) / sizeof (float); + outcount++; + } + + if (dists[i] == 0 || dists[i+1] == 0) + continue; + + if ( (dists[i] > 0) == (dists[i+1] > 0) ) + continue; + + // split it into a new vertex + frac = dists[i] / (dists[i] - dists[i+1]); + + vert2 = instep + sizeof (vec5_t) / sizeof (float); + + outstep[0] = instep[0] + frac*(vert2[0] - instep[0]); + outstep[1] = instep[1] + frac*(vert2[1] - instep[1]); + outstep[2] = instep[2] + frac*(vert2[2] - instep[2]); + outstep[3] = instep[3] + frac*(vert2[3] - instep[3]); + outstep[4] = instep[4] + frac*(vert2[4] - instep[4]); + + outstep += sizeof (vec5_t) / sizeof (float); + outcount++; + } + + return outcount; +} + +#ifdef USEFPM +int R_ClipSpriteFaceFPM (int nump, clipplane_FPM_t *pclipplane) +{ + int i, outcount; + fixedpoint_t dists[MAXWORKINGVERTS+1]; + fixedpoint_t frac, clipdist, *pclipnormal; + fixedpoint_t *in, *instep, *outstep, *vert2; + + clipdist = pclipplane->dist; + pclipnormal = pclipplane->normal; + +// calc dists + if (clip_current) + { + in = clip_vertsFPM[1][0]; + outstep = clip_vertsFPM[0][0]; + clip_current = 0; + } + else + { + in = clip_vertsFPM[0][0]; + outstep = clip_vertsFPM[1][0]; + clip_current = 1; + } + + instep = in; + for (i=0 ; i= 0) + { + Q_memcpy (outstep, instep, sizeof (vec5_FPM_t)); + outstep += sizeof (vec5_FPM_t) / sizeof (fixedpoint_t); + outcount++; + } + + if (dists[i] == 0 || dists[i+1] == 0) + continue; + + if ( (dists[i] > 0) == (dists[i+1] > 0) ) + continue; + + // split it into a new vertex + frac = FPM_DIV(dists[i], FPM_SUB(dists[i], dists[i+1])); + + vert2 = instep + sizeof (vec5_FPM_t) / sizeof (fixedpoint_t); + + outstep[0] = FPM_ADD(instep[0], FPM_MUL(frac, FPM_SUB(vert2[0], instep[0]))); + outstep[1] = FPM_ADD(instep[1], FPM_MUL(frac, FPM_SUB(vert2[1], instep[1]))); + outstep[2] = FPM_ADD(instep[2], FPM_MUL(frac, FPM_SUB(vert2[2], instep[2]))); + outstep[3] = FPM_ADD(instep[3], FPM_MUL(frac, FPM_SUB(vert2[3], instep[3]))); + outstep[4] = FPM_ADD(instep[4], FPM_MUL(frac, FPM_SUB(vert2[4], instep[4]))); + + outstep += sizeof (vec5_FPM_t) / sizeof (fixedpoint_t); + outcount++; + } + + return outcount; +} +#endif //USEFPM + +/* +================ +R_SetupAndDrawSprite +================ +*/ +void R_SetupAndDrawSprite () +{ + int i, nump; + float dot, scale, *pv; + vec5_t *pverts; + vec3_t left, up, right, down, transformed, local; + emitpoint_t outverts[MAXWORKINGVERTS+1], *pout; + + dot = DotProduct (r_spritedesc.vpn, modelorg); + +// backface cull + if (dot >= 0) + return; + +// build the sprite poster in worldspace + VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->right, right); + VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->up, up); + VectorScale (r_spritedesc.vright, r_spritedesc.pspriteframe->left, left); + VectorScale (r_spritedesc.vup, r_spritedesc.pspriteframe->down, down); + + pverts = clip_verts[0]; + + pverts[0][0] = r_entorigin[0] + up[0] + left[0]; + pverts[0][1] = r_entorigin[1] + up[1] + left[1]; + pverts[0][2] = r_entorigin[2] + up[2] + left[2]; + pverts[0][3] = 0; + pverts[0][4] = 0; + + pverts[1][0] = r_entorigin[0] + up[0] + right[0]; + pverts[1][1] = r_entorigin[1] + up[1] + right[1]; + pverts[1][2] = r_entorigin[2] + up[2] + right[2]; + pverts[1][3] = (float)sprite_width; + pverts[1][4] = 0; + + pverts[2][0] = r_entorigin[0] + down[0] + right[0]; + pverts[2][1] = r_entorigin[1] + down[1] + right[1]; + pverts[2][2] = r_entorigin[2] + down[2] + right[2]; + pverts[2][3] = (float)sprite_width; + pverts[2][4] = (float)sprite_height; + + pverts[3][0] = r_entorigin[0] + down[0] + left[0]; + pverts[3][1] = r_entorigin[1] + down[1] + left[1]; + pverts[3][2] = r_entorigin[2] + down[2] + left[2]; + pverts[3][3] = 0; + pverts[3][4] = (float)sprite_height; + +// clip to the frustum in worldspace + nump = 4; + clip_current = 0; + + for (i=0 ; i<4 ; i++) + { + nump = R_ClipSpriteFace (nump, &view_clipplanes[i]); + if (nump < 3) + return; + if (nump >= MAXWORKINGVERTS) + Sys_Error("R_SetupAndDrawSprite: too many points"); + } + +// transform vertices into viewspace and project + pv = &clip_verts[clip_current][0][0]; + r_spritedesc.nearzi = -999999; + + for (i=0 ; izi = (float)(1.0 / transformed[2]); + if (pout->zi > r_spritedesc.nearzi) + r_spritedesc.nearzi = pout->zi; + + pout->s = pv[3]; + pout->t = pv[4]; + + scale = xscale * pout->zi; + pout->u = (xcenter + scale * transformed[0]); + + scale = yscale * pout->zi; + pout->v = (ycenter - scale * transformed[1]); + + pv += sizeof (vec5_t) / sizeof (*pv); + } + +// draw it + r_spritedesc.nump = nump; + r_spritedesc.pverts = outverts; + D_DrawSprite (); +} + +#ifdef USEFPM +void R_SetupAndDrawSpriteFPM () +{ + int i, nump; + fixedpoint_t dot, scale, *pv; + vec5_FPM_t *pverts; + vec3_FPM_t left, up, right, down, transformed, local; + emitpoint_FPM_t outverts[MAXWORKINGVERTS+1], *pout; + + dot = DotProductFPM (r_spritedescFPM.vpn, modelorgFPM); + +// backface cull + if (dot >= 0) + return; + +// build the sprite poster in worldspace + VectorScaleFPM (r_spritedescFPM.vright, r_spritedescFPM.pspriteframe->right, right); + VectorScaleFPM (r_spritedescFPM.vup, r_spritedescFPM.pspriteframe->up, up); + VectorScaleFPM (r_spritedescFPM.vright, r_spritedescFPM.pspriteframe->left, left); + VectorScaleFPM (r_spritedescFPM.vup, r_spritedescFPM.pspriteframe->down, down); + + pverts = clip_vertsFPM[0]; + + pverts[0][0] = FPM_ADD3(r_entoriginFPM[0], up[0], left[0]); + pverts[0][1] = FPM_ADD3(r_entoriginFPM[1], up[1], left[1]); + pverts[0][2] = FPM_ADD3(r_entoriginFPM[2], up[2], left[2]); + pverts[0][3] = 0; + pverts[0][4] = 0; + + pverts[1][0] = FPM_ADD3(r_entoriginFPM[0], up[0], right[0]); + pverts[1][1] = FPM_ADD3(r_entoriginFPM[1], up[1], right[1]); + pverts[1][2] = FPM_ADD3(r_entoriginFPM[2], up[2], right[2]); + pverts[1][3] = FPM_FROMLONG(sprite_width); + pverts[1][4] = 0; + + pverts[2][0] = FPM_ADD3(r_entoriginFPM[0], down[0], right[0]); + pverts[2][1] = FPM_ADD3(r_entoriginFPM[1], down[1], right[1]); + pverts[2][2] = FPM_ADD3(r_entoriginFPM[2], down[2], right[2]); + pverts[2][3] = FPM_FROMLONG(sprite_width); + pverts[2][4] = FPM_FROMLONG(sprite_height); + + pverts[3][0] = FPM_ADD3(r_entoriginFPM[0], down[0], left[0]); + pverts[3][1] = FPM_ADD3(r_entoriginFPM[1], down[1], left[1]); + pverts[3][2] = FPM_ADD3(r_entoriginFPM[2], down[2], left[2]); + pverts[3][3] = 0; + pverts[3][4] = FPM_FROMLONG(sprite_height); + +// clip to the frustum in worldspace + nump = 4; + clip_current = 0; + + for (i=0 ; i<4 ; i++) + { + nump = R_ClipSpriteFaceFPM (nump, &view_clipplanesFPM[i]); + if (nump < 3) + return; + if (nump >= MAXWORKINGVERTS) + Sys_Error("R_SetupAndDrawSprite: too many points"); + } + +// transform vertices into viewspace and project + pv = &clip_vertsFPM[clip_current][0][0]; + r_spritedescFPM.nearzi = FPM_FROMLONG(-999999); + + for (i=0 ; izi = FPM_INV(transformed[2]); + if (pout->zi > r_spritedescFPM.nearzi) + r_spritedescFPM.nearzi = pout->zi; + + pout->s = pv[3]; + pout->t = pv[4]; + + scale = FPM_MUL(xscaleFPM, pout->zi); + pout->u = FPM_ADD(xcenterFPM, FPM_MUL(scale, transformed[0])); + + scale = FPM_MUL(yscaleFPM, pout->zi); + pout->v = FPM_SUB(ycenterFPM, FPM_MUL(scale, transformed[1])); + + pv += sizeof (vec5_FPM_t) / sizeof (*pv); + } + +// draw it + r_spritedescFPM.nump = nump; + r_spritedescFPM.pverts = outverts; + D_DrawSpriteFPM (); +} +#endif //USEFPM + +/* +================ +R_GetSpriteframe +================ +*/ +mspriteframe_t *R_GetSpriteframe (msprite_t *psprite) +{ + mspritegroup_t *pspritegroup; + mspriteframe_t *pspriteframe; + int i, numframes, frame; + float *pintervals, fullinterval, targettime, time; + + frame = currententity->frame; + + if ((frame >= psprite->numframes) || (frame < 0)) + { + Con_Printf ("R_DrawSprite: no such frame %d\n", frame); + frame = 0; + } + + if (psprite->frames[frame].type == SPR_SINGLE) + { + pspriteframe = psprite->frames[frame].frameptr; + } + else + { + pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; + pintervals = pspritegroup->intervals; + numframes = pspritegroup->numframes; + fullinterval = pintervals[numframes-1]; + + time = (float)(cl.time + currententity->syncbase); + + // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values + // are positive, so we don't have to worry about division by 0 + targettime = time - ((int)(time / fullinterval)) * fullinterval; + + for (i=0 ; i<(numframes-1) ; i++) + { + if (pintervals[i] > targettime) + break; + } + + pspriteframe = pspritegroup->frames[i]; + } + + return pspriteframe; +} + +#ifdef USEFPM +mspriteframe_FPM_t *R_GetSpriteframeFPM (msprite_FPM_t *psprite) +{ + mspritegroup_FPM_t *pspritegroup; + mspriteframe_FPM_t *pspriteframe; + int i, numframes, frame; + fixedpoint_t *pintervals, fullinterval, targettime, time; + + frame = currententityFPM->frame; + + if ((frame >= psprite->numframes) || (frame < 0)) + { + Con_Printf ("R_DrawSprite: no such frame %d\n", frame); + frame = 0; + } + + if (psprite->frames[frame].type == SPR_SINGLE) + { + pspriteframe = psprite->frames[frame].frameptr; + } + else + { + pspritegroup = (mspritegroup_FPM_t *)psprite->frames[frame].frameptr; + pintervals = pspritegroup->intervals; + numframes = pspritegroup->numframes; + fullinterval = pintervals[numframes-1]; + + time = FPM_FROMFLOAT(clFPM.time + currententityFPM->syncbase); + + // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values + // are positive, so we don't have to worry about division by 0 + targettime = FPM_SUB(time, FPM_MUL(FPM_DIV(time, fullinterval), fullinterval)); + + for (i=0 ; i<(numframes-1) ; i++) + { + if (pintervals[i] > targettime) + break; + } + + pspriteframe = pspritegroup->frames[i]; + } + + return pspriteframe; +} +#endif //USEFPM + +/* +================ +R_DrawSprite +================ +*/ +void R_DrawSprite (void) +{ + int i; + msprite_t *psprite; + vec3_t tvec; + float dot, angle, sr, cr; + + psprite = currententity->model->cache.data; + + r_spritedesc.pspriteframe = R_GetSpriteframe (psprite); + + sprite_width = r_spritedesc.pspriteframe->width; + sprite_height = r_spritedesc.pspriteframe->height; + +// TODO: make this caller-selectable + if (psprite->type == SPR_FACING_UPRIGHT) + { + // generate the sprite's axes, with vup straight up in worldspace, and + // r_spritedesc.vright perpendicular to modelorg. + // This will not work if the view direction is very close to straight up or + // down, because the cross product will be between two nearly parallel + // vectors and starts to approach an undefined state, so we don't draw if + // the two vectors are less than 1 degree apart + tvec[0] = -modelorg[0]; + tvec[1] = -modelorg[1]; + tvec[2] = -modelorg[2]; + VectorNormalize (tvec); + dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because + // r_spritedesc.vup is 0, 0, 1 + if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848 + return; + r_spritedesc.vup[0] = 0; + r_spritedesc.vup[1] = 0; + r_spritedesc.vup[2] = 1; + r_spritedesc.vright[0] = tvec[1]; + // CrossProduct(r_spritedesc.vup, -modelorg, + r_spritedesc.vright[1] = -tvec[0]; + // r_spritedesc.vright) + r_spritedesc.vright[2] = 0; + VectorNormalize (r_spritedesc.vright); + r_spritedesc.vpn[0] = -r_spritedesc.vright[1]; + r_spritedesc.vpn[1] = r_spritedesc.vright[0]; + r_spritedesc.vpn[2] = 0; + // CrossProduct (r_spritedesc.vright, r_spritedesc.vup, + // r_spritedesc.vpn) + } + else if (psprite->type == SPR_VP_PARALLEL) + { + // generate the sprite's axes, completely parallel to the viewplane. There + // are no problem situations, because the sprite is always in the same + // position relative to the viewer + for (i=0 ; i<3 ; i++) + { + r_spritedesc.vup[i] = vup[i]; + r_spritedesc.vright[i] = vright[i]; + r_spritedesc.vpn[i] = vpn[i]; + } + } + else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT) + { + // generate the sprite's axes, with vup straight up in worldspace, and + // r_spritedesc.vright parallel to the viewplane. + // This will not work if the view direction is very close to straight up or + // down, because the cross product will be between two nearly parallel + // vectors and starts to approach an undefined state, so we don't draw if + // the two vectors are less than 1 degree apart + dot = vpn[2]; // same as DotProduct (vpn, r_spritedesc.vup) because + // r_spritedesc.vup is 0, 0, 1 + if ((dot > 0.999848) || (dot < -0.999848)) // cos(1 degree) = 0.999848 + return; + r_spritedesc.vup[0] = 0; + r_spritedesc.vup[1] = 0; + r_spritedesc.vup[2] = 1; + r_spritedesc.vright[0] = vpn[1]; + // CrossProduct (r_spritedesc.vup, vpn, + r_spritedesc.vright[1] = -vpn[0]; // r_spritedesc.vright) + r_spritedesc.vright[2] = 0; + VectorNormalize (r_spritedesc.vright); + r_spritedesc.vpn[0] = -r_spritedesc.vright[1]; + r_spritedesc.vpn[1] = r_spritedesc.vright[0]; + r_spritedesc.vpn[2] = 0; + // CrossProduct (r_spritedesc.vright, r_spritedesc.vup, + // r_spritedesc.vpn) + } + else if (psprite->type == SPR_ORIENTED) + { + // generate the sprite's axes, according to the sprite's world orientation + AngleVectors (currententity->angles, r_spritedesc.vpn, + r_spritedesc.vright, r_spritedesc.vup); + } + else if (psprite->type == SPR_VP_PARALLEL_ORIENTED) + { + // generate the sprite's axes, parallel to the viewplane, but rotated in + // that plane around the center according to the sprite entity's roll + // angle. So vpn stays the same, but vright and vup rotate + angle = (float)(currententity->angles[ROLL] * (M_PI*2 / 360)); + sr = (float)(sin(angle)); + cr = (float)(cos(angle)); + + for (i=0 ; i<3 ; i++) + { + r_spritedesc.vpn[i] = vpn[i]; + r_spritedesc.vright[i] = vright[i] * cr + vup[i] * sr; + r_spritedesc.vup[i] = vright[i] * -sr + vup[i] * cr; + } + } + else + { + Sys_Error ("R_DrawSprite: Bad sprite type %d", psprite->type); + } + + R_RotateSprite (psprite->beamlength); + + R_SetupAndDrawSprite (); +} + +#ifdef USEFPM +void R_DrawSpriteFPM (void) +{ + int i; + msprite_FPM_t *psprite; + vec3_FPM_t tvec; + fixedpoint_t dot, angle, sr, cr; + + psprite = currententityFPM->model->cache.data; + + r_spritedescFPM.pspriteframe = R_GetSpriteframeFPM (psprite); + + sprite_width = r_spritedescFPM.pspriteframe->width; + sprite_height = r_spritedescFPM.pspriteframe->height; + +// TODO: make this caller-selectable + if (psprite->type == SPR_FACING_UPRIGHT) + { + // generate the sprite's axes, with vup straight up in worldspace, and + // r_spritedesc.vright perpendicular to modelorg. + // This will not work if the view direction is very close to straight up or + // down, because the cross product will be between two nearly parallel + // vectors and starts to approach an undefined state, so we don't draw if + // the two vectors are less than 1 degree apart + tvec[0] = -modelorgFPM[0]; + tvec[1] = -modelorgFPM[1]; + tvec[2] = -modelorgFPM[2]; + VectorNormalizeFPM (tvec); + dot = tvec[2]; // same as DotProduct (tvec, r_spritedesc.vup) because + // r_spritedesc.vup is 0, 0, 1 + if ((dot > FPM_FROMFLOAT(0.999848)) || (dot < FPM_FROMFLOAT(-0.999848))) // cos(1 degree) = 0.999848 + return; + r_spritedescFPM.vup[0] = 0; + r_spritedescFPM.vup[1] = 0; + r_spritedescFPM.vup[2] = FPM_FROMLONG(1); + r_spritedescFPM.vright[0] = tvec[1]; + // CrossProduct(r_spritedesc.vup, -modelorg, + r_spritedescFPM.vright[1] = -tvec[0]; + // r_spritedesc.vright) + r_spritedescFPM.vright[2] = 0; + VectorNormalizeFPM (r_spritedescFPM.vright); + r_spritedescFPM.vpn[0] = -r_spritedescFPM.vright[1]; + r_spritedescFPM.vpn[1] = r_spritedescFPM.vright[0]; + r_spritedescFPM.vpn[2] = 0; + // CrossProduct (r_spritedesc.vright, r_spritedesc.vup, + // r_spritedesc.vpn) + } + else if (psprite->type == SPR_VP_PARALLEL) + { + // generate the sprite's axes, completely parallel to the viewplane. There + // are no problem situations, because the sprite is always in the same + // position relative to the viewer + for (i=0 ; i<3 ; i++) + { + r_spritedescFPM.vup[i] = vupFPM[i]; + r_spritedescFPM.vright[i] = vrightFPM[i]; + r_spritedescFPM.vpn[i] = vpnFPM[i]; + } + } + else if (psprite->type == SPR_VP_PARALLEL_UPRIGHT) + { + // generate the sprite's axes, with vup straight up in worldspace, and + // r_spritedesc.vright parallel to the viewplane. + // This will not work if the view direction is very close to straight up or + // down, because the cross product will be between two nearly parallel + // vectors and starts to approach an undefined state, so we don't draw if + // the two vectors are less than 1 degree apart + dot = vpnFPM[2]; // same as DotProduct (vpn, r_spritedesc.vup) because + // r_spritedesc.vup is 0, 0, 1 + if ((dot > FPM_FROMFLOAT(0.999848)) || (dot < FPM_FROMFLOAT(-0.999848))) // cos(1 degree) = 0.999848 + return; + r_spritedescFPM.vup[0] = 0; + r_spritedescFPM.vup[1] = 0; + r_spritedescFPM.vup[2] = FPM_FROMLONG(1); + r_spritedescFPM.vright[0] = vpnFPM[1]; + // CrossProduct (r_spritedesc.vup, vpn, + r_spritedescFPM.vright[1] = -vpnFPM[0]; // r_spritedesc.vright) + r_spritedescFPM.vright[2] = 0; + VectorNormalizeFPM (r_spritedescFPM.vright); + r_spritedescFPM.vpn[0] = -r_spritedescFPM.vright[1]; + r_spritedescFPM.vpn[1] = r_spritedescFPM.vright[0]; + r_spritedescFPM.vpn[2] = 0; + // CrossProduct (r_spritedesc.vright, r_spritedesc.vup, + // r_spritedesc.vpn) + } + else if (psprite->type == SPR_ORIENTED) + { + // generate the sprite's axes, according to the sprite's world orientation + AngleVectorsFPM (currententityFPM->angles, r_spritedescFPM.vpn, + r_spritedescFPM.vright, r_spritedescFPM.vup); + } + else if (psprite->type == SPR_VP_PARALLEL_ORIENTED) + { + // generate the sprite's axes, parallel to the viewplane, but rotated in + // that plane around the center according to the sprite entity's roll + // angle. So vpn stays the same, but vright and vup rotate + angle = FPM_MUL(currententityFPM->angles[ROLL], FPM_DIV(FPM_PI,FPM_FROMLONG(180))); + sr = FPM_SIN(angle); + cr = FPM_COS(angle); + + for (i=0 ; i<3 ; i++) + { + r_spritedescFPM.vpn[i] = vpnFPM[i]; + r_spritedescFPM.vright[i] = FPM_ADD(FPM_MUL(vrightFPM[i], cr), FPM_MUL(vupFPM[i], sr)); + r_spritedescFPM.vup[i] = FPM_ADD(FPM_MUL(vrightFPM[i], -sr), FPM_MUL(vupFPM[i], cr)); + } + } + else + { + Sys_Error ("R_DrawSprite: Bad sprite type %d", psprite->type); + } + + R_RotateSpriteFPM (psprite->beamlength); + + R_SetupAndDrawSpriteFPM (); +} +#endif //USEFPM diff --git a/project/jni/application/quake/source/r_surf.c b/project/jni/application/quake/source/r_surf.c new file mode 100644 index 000000000..ec4b61d2b --- /dev/null +++ b/project/jni/application/quake/source/r_surf.c @@ -0,0 +1,937 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_surf.c: surface-related refresh code + +#include "quakedef.h" +#include "r_local.h" + +drawsurf_t r_drawsurf; +#ifdef USEFPM +drawsurf_FPM_t r_drawsurfFPM; +#endif //USEFPM + +int lightleft, sourcesstep, blocksize, sourcetstep; +int lightdelta, lightdeltastep; +int lightright, lightleftstep, lightrightstep, blockdivshift; +unsigned blockdivmask; +void *prowdestbase; +unsigned char *pbasesource; +int surfrowbytes; // used by ASM files +unsigned *r_lightptr; +int r_stepback; +int r_lightwidth; +int r_numhblocks, r_numvblocks; +unsigned char *r_source, *r_sourcemax; + +void R_DrawSurfaceBlock8_mip0 (void); +void R_DrawSurfaceBlock8_mip1 (void); +void R_DrawSurfaceBlock8_mip2 (void); +void R_DrawSurfaceBlock8_mip3 (void); + +static void (*surfmiptable[4])(void) = { + R_DrawSurfaceBlock8_mip0, + R_DrawSurfaceBlock8_mip1, + R_DrawSurfaceBlock8_mip2, + R_DrawSurfaceBlock8_mip3 +}; + + + +unsigned blocklights[18*18]; + +/* +=============== +R_AddDynamicLights +=============== +*/ +void R_AddDynamicLights (void) +{ + msurface_t *surf; + int lnum; + int sd, td; + float dist, rad, minlight; + vec3_t impact, local; + int s, t; + int i; + int smax, tmax; + mtexinfo_t *tex; + + surf = r_drawsurf.surf; + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + tex = surf->texinfo; + + for (lnum=0 ; lnumdlightbits & (1<plane->normal) - + surf->plane->dist; + rad -= (float)fabs(dist); + minlight = cl_dlights[lnum].minlight; + if (rad < minlight) + continue; + minlight = rad - minlight; + + for (i=0 ; i<3 ; i++) + { + impact[i] = cl_dlights[lnum].origin[i] - + surf->plane->normal[i]*dist; + } + + local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3]; + local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3]; + + local[0] -= surf->texturemins[0]; + local[1] -= surf->texturemins[1]; + + for (t = 0 ; t td) + dist = (float)(sd + (td>>1)); + else + dist = (float)(td + (sd>>1)); + if (dist < minlight) +#ifdef QUAKE2 + { + unsigned temp; + temp = (rad - dist)*256; + i = t*smax + s; + if (!cl_dlights[lnum].dark) + blocklights[i] += temp; + else + { + if (blocklights[i] > temp) + blocklights[i] -= temp; + else + blocklights[i] = 0; + } + } +#else + blocklights[t*smax + s] += (unsigned int)(rad - dist)*256; +#endif + } + } + } +} + +#ifdef USEFPM +void R_AddDynamicLightsFPM (void) +{ + msurface_FPM_t *surf; + int lnum; + int sd, td; + fixedpoint_t dist, rad, minlight; + vec3_FPM_t impact, local; + int s, t; + int i; + int smax, tmax; + mtexinfo_FPM_t *tex; + + surf = r_drawsurfFPM.surf; + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + tex = surf->texinfo; + + for (lnum=0 ; lnumdlightbits & (1<plane->normal), + surf->plane->dist); + rad = FPM_SUB(rad, FPM_ABS(dist)); + minlight = cl_dlightsFPM[lnum].minlight; + if (rad < minlight) + continue; + minlight = FPM_SUB(rad, minlight); + + for (i=0 ; i<3 ; i++) + { + impact[i] = FPM_SUB(cl_dlightsFPM[lnum].origin[i], + FPM_MUL(surf->plane->normal[i],dist)); + } + + local[0] = FPM_ADD(DotProductFPM (impact, tex->vecs[0]), tex->vecs[0][3]); + local[1] = FPM_ADD(DotProductFPM (impact, tex->vecs[1]), tex->vecs[1][3]); + + local[0] = FPM_SUB(local[0], surf->texturemins[0]); + local[1] = FPM_SUB(local[1], surf->texturemins[1]); + + for (t = 0 ; t td) + dist = FPM_FROMLONG(sd + (td>>1)); + else + dist = FPM_FROMLONG(td + (sd>>1)); + if (dist < minlight) +#ifdef QUAKE2 + { + unsigned temp; + temp = FPM_TOLONG(FPM_MUL(FPM_SUB(rad, dist),FPM_FROMLONG(256))); + i = t*smax + s; + if (!cl_dlights[lnum].dark) + blocklights[i] += temp; + else + { + if (blocklights[i] > temp) + blocklights[i] -= temp; + else + blocklights[i] = 0; + } + } +#else + blocklights[t*smax + s] += FPM_MUL(FPM_SUB(rad, dist),FPM_FROMLONG(256)); +#endif + } + } + } +} +#endif //USEFPM + +/* +=============== +R_BuildLightMap + +Combine and scale multiple lightmaps into the 8.8 format in blocklights +=============== +*/ +void R_BuildLightMap (void) +{ + int smax, tmax; + int t; + int i, size; + byte *lightmap; + unsigned scale; + int maps; + msurface_t *surf; + + surf = r_drawsurf.surf; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + size = smax*tmax; + lightmap = surf->samples; + + if (r_fullbright.value || !cl.worldmodel->lightdata) + { + for (i=0 ; istyles[maps] != 255 ; + maps++) + { + scale = r_drawsurf.lightadj[maps]; // 8.8 fraction + for (i=0 ; idlightframe == r_framecount) + R_AddDynamicLights (); + +// bound, invert, and shift + for (i=0 ; i> (8 - VID_CBITS); + + if (t < (1 << 6)) + t = (1 << 6); + + blocklights[i] = t; + } +} + +#ifdef USEFPM +void R_BuildLightMapFPM (void) +{ + int smax, tmax; + int t; + int i, size; + byte *lightmap; + unsigned scale; + int maps; + msurface_FPM_t *surf; + + surf = r_drawsurfFPM.surf; + + smax = (surf->extents[0]>>4)+1; + tmax = (surf->extents[1]>>4)+1; + size = smax*tmax; + lightmap = surf->samples; + + if (r_fullbright.value || !clFPM.worldmodel->lightdata) + { + for (i=0 ; istyles[maps] != 255 ; + maps++) + { + scale = r_drawsurfFPM.lightadj[maps]; // 8.8 fraction + for (i=0 ; idlightframe == r_framecount) + R_AddDynamicLightsFPM (); + +// bound, invert, and shift + for (i=0 ; i> (8 - VID_CBITS); + + if (t < (1 << 6)) + t = (1 << 6); + + blocklights[i] = t; + } +} +#endif //USEFPM + +/* +=============== +R_TextureAnimation + +Returns the proper texture for a given time and base texture +=============== +*/ +texture_t *R_TextureAnimation (texture_t *base) +{ + int reletive; + int count; + + if (currententity->frame) + { + if (base->alternate_anims) + base = base->alternate_anims; + } + + if (!base->anim_total) + return base; + + reletive = (int)(cl.time*10) % base->anim_total; + + count = 0; + while (base->anim_min > reletive || base->anim_max <= reletive) + { + base = base->anim_next; + if (!base) + Sys_Error ("R_TextureAnimation: broken cycle"); + if (++count > 100) + Sys_Error ("R_TextureAnimation: infinite cycle"); + } + + return base; +} + +#ifdef USEFPM +texture_t *R_TextureAnimationFPM (texture_t *base) +{ + int reletive; + int count; + + if (currententityFPM->frame) + { + if (base->alternate_anims) + base = base->alternate_anims; + } + + if (!base->anim_total) + return base; + + reletive = (int)(cl.time*10) % base->anim_total; + + count = 0; + while (base->anim_min > reletive || base->anim_max <= reletive) + { + base = base->anim_next; + if (!base) + Sys_Error ("R_TextureAnimation: broken cycle"); + if (++count > 100) + Sys_Error ("R_TextureAnimation: infinite cycle"); + } + + return base; +} +#endif //USEFPM + +/* +=============== +R_DrawSurface +=============== +*/ +void R_DrawSurface (void) +{ + unsigned char *basetptr; + int smax, tmax, twidth; + int u; + int soffset, basetoffset, texwidth; + int horzblockstep; + unsigned char *pcolumndest; + void (*pblockdrawer)(void); + texture_t *mt; + +// calculate the lightings + R_BuildLightMap (); + + surfrowbytes = r_drawsurf.rowbytes; + + mt = r_drawsurf.texture; + + r_source = (byte *)mt + mt->offsets[r_drawsurf.surfmip]; + +// the fractional light values should range from 0 to (VID_GRADES - 1) << 16 +// from a source range of 0 - 255 + + texwidth = mt->width >> r_drawsurf.surfmip; + + blocksize = 16 >> r_drawsurf.surfmip; + blockdivshift = 4 - r_drawsurf.surfmip; + blockdivmask = (1 << blockdivshift) - 1; + + r_lightwidth = (r_drawsurf.surf->extents[0]>>4)+1; + + r_numhblocks = r_drawsurf.surfwidth >> blockdivshift; + r_numvblocks = r_drawsurf.surfheight >> blockdivshift; + +//============================== + + if (r_pixbytes == 1) + { + pblockdrawer = surfmiptable[r_drawsurf.surfmip]; + // TODO: only needs to be set when there is a display settings change + horzblockstep = blocksize; + } + else + { + pblockdrawer = R_DrawSurfaceBlock16; + // TODO: only needs to be set when there is a display settings change + horzblockstep = blocksize << 1; + } + + smax = mt->width >> r_drawsurf.surfmip; + twidth = texwidth; + tmax = mt->height >> r_drawsurf.surfmip; + sourcetstep = texwidth; + r_stepback = tmax * twidth; + + r_sourcemax = r_source + (tmax * smax); + + soffset = r_drawsurf.surf->texturemins[0]; + basetoffset = r_drawsurf.surf->texturemins[1]; + +// << 16 components are to guarantee positive values for % + soffset = ((soffset >> r_drawsurf.surfmip) + (smax << 16)) % smax; + basetptr = &r_source[((((basetoffset >> r_drawsurf.surfmip) + + (tmax << 16)) % tmax) * twidth)]; + + pcolumndest = r_drawsurf.surfdat; + + for (u=0 ; u= smax) + soffset = 0; + + pcolumndest += horzblockstep; + } +} + +#ifdef USEFPM +void R_DrawSurfaceFPM (void) +{ + unsigned char *basetptr; + int smax, tmax, twidth; + int u; + int soffset, basetoffset, texwidth; + int horzblockstep; + unsigned char *pcolumndest; + void (*pblockdrawer)(void); + texture_t *mt; + +// calculate the lightings + R_BuildLightMapFPM (); + + surfrowbytes = r_drawsurfFPM.rowbytes; + + mt = r_drawsurfFPM.texture; + + r_source = (byte *)mt + mt->offsets[r_drawsurfFPM.surfmip]; + +// the fractional light values should range from 0 to (VID_GRADES - 1) << 16 +// from a source range of 0 - 255 + + texwidth = mt->width >> r_drawsurfFPM.surfmip; + + blocksize = 16 >> r_drawsurfFPM.surfmip; + blockdivshift = 4 - r_drawsurfFPM.surfmip; + blockdivmask = (1 << blockdivshift) - 1; + + r_lightwidth = (r_drawsurfFPM.surf->extents[0]>>4)+1; + + r_numhblocks = r_drawsurfFPM.surfwidth >> blockdivshift; + r_numvblocks = r_drawsurfFPM.surfheight >> blockdivshift; + +//============================== + + if (r_pixbytes == 1) + { + pblockdrawer = surfmiptable[r_drawsurfFPM.surfmip]; + // TODO: only needs to be set when there is a display settings change + horzblockstep = blocksize; + } + else + { + pblockdrawer = R_DrawSurfaceBlock16; + // TODO: only needs to be set when there is a display settings change + horzblockstep = blocksize << 1; + } + + smax = mt->width >> r_drawsurfFPM.surfmip; + twidth = texwidth; + tmax = mt->height >> r_drawsurfFPM.surfmip; + sourcetstep = texwidth; + r_stepback = tmax * twidth; + + r_sourcemax = r_source + (tmax * smax); + + soffset = r_drawsurfFPM.surf->texturemins[0]; + basetoffset = r_drawsurfFPM.surf->texturemins[1]; + +// << 16 components are to guarantee positive values for % + soffset = ((soffset >> r_drawsurfFPM.surfmip) + (smax << 16)) % smax; + basetptr = &r_source[((((basetoffset >> r_drawsurfFPM.surfmip) + + (tmax << 16)) % tmax) * twidth)]; + + pcolumndest = r_drawsurfFPM.surfdat; + + for (u=0 ; u= smax) + soffset = 0; + + pcolumndest += horzblockstep; + } +} +#endif //USEFPM + +//============================================================================= + +#if !id386 + +/* +================ +R_DrawSurfaceBlock8_mip0 +================ +*/ +void R_DrawSurfaceBlock8_mip0 (void) +{ + int v, i, b, lightstep, lighttemp, light; + unsigned char pix, *psource, *prowdest; + + psource = pbasesource; + prowdest = prowdestbase; + + for (v=0 ; v> 4; + lightrightstep = (r_lightptr[1] - lightright) >> 4; + + for (i=0 ; i<16 ; i++) + { + lighttemp = lightleft - lightright; + lightstep = lighttemp >> 4; + + light = lightright; + + for (b=15; b>=0; b--) + { + pix = psource[b]; + prowdest[b] = ((unsigned char *)vid.colormap) + [(light & 0xFF00) + pix]; + light += lightstep; + } + + psource += sourcetstep; + lightright += lightrightstep; + lightleft += lightleftstep; + prowdest += surfrowbytes; + } + + if (psource >= r_sourcemax) + psource -= r_stepback; + } +} + + +/* +================ +R_DrawSurfaceBlock8_mip1 +================ +*/ +void R_DrawSurfaceBlock8_mip1 (void) +{ + int v, i, b, lightstep, lighttemp, light; + unsigned char pix, *psource, *prowdest; + + psource = pbasesource; + prowdest = prowdestbase; + + for (v=0 ; v> 3; + lightrightstep = (r_lightptr[1] - lightright) >> 3; + + for (i=0 ; i<8 ; i++) + { + lighttemp = lightleft - lightright; + lightstep = lighttemp >> 3; + + light = lightright; + + for (b=7; b>=0; b--) + { + pix = psource[b]; + prowdest[b] = ((unsigned char *)vid.colormap) + [(light & 0xFF00) + pix]; + light += lightstep; + } + + psource += sourcetstep; + lightright += lightrightstep; + lightleft += lightleftstep; + prowdest += surfrowbytes; + } + + if (psource >= r_sourcemax) + psource -= r_stepback; + } +} + + +/* +================ +R_DrawSurfaceBlock8_mip2 +================ +*/ +void R_DrawSurfaceBlock8_mip2 (void) +{ + int v, i, b, lightstep, lighttemp, light; + unsigned char pix, *psource, *prowdest; + + psource = pbasesource; + prowdest = prowdestbase; + + for (v=0 ; v> 2; + lightrightstep = (r_lightptr[1] - lightright) >> 2; + + for (i=0 ; i<4 ; i++) + { + lighttemp = lightleft - lightright; + lightstep = lighttemp >> 2; + + light = lightright; + + for (b=3; b>=0; b--) + { + pix = psource[b]; + prowdest[b] = ((unsigned char *)vid.colormap) + [(light & 0xFF00) + pix]; + light += lightstep; + } + + psource += sourcetstep; + lightright += lightrightstep; + lightleft += lightleftstep; + prowdest += surfrowbytes; + } + + if (psource >= r_sourcemax) + psource -= r_stepback; + } +} + + +/* +================ +R_DrawSurfaceBlock8_mip3 +================ +*/ +void R_DrawSurfaceBlock8_mip3 (void) +{ + int v, i, b, lightstep, lighttemp, light; + unsigned char pix, *psource, *prowdest; + + psource = pbasesource; + prowdest = prowdestbase; + + for (v=0 ; v> 1; + lightrightstep = (r_lightptr[1] - lightright) >> 1; + + for (i=0 ; i<2 ; i++) + { + lighttemp = lightleft - lightright; + lightstep = lighttemp >> 1; + + light = lightright; + + for (b=1; b>=0; b--) + { + pix = psource[b]; + prowdest[b] = ((unsigned char *)vid.colormap) + [(light & 0xFF00) + pix]; + light += lightstep; + } + + psource += sourcetstep; + lightright += lightrightstep; + lightleft += lightleftstep; + prowdest += surfrowbytes; + } + + if (psource >= r_sourcemax) + psource -= r_stepback; + } +} + + +/* +================ +R_DrawSurfaceBlock16 + +FIXME: make this work +================ +*/ +void R_DrawSurfaceBlock16 (void) +{ + int k; + unsigned char *psource; + int lighttemp, lightstep, light; + unsigned short *prowdest; + + prowdest = (unsigned short *)prowdestbase; + + for (k=0 ; k> blockdivshift; + + light = lightleft; + pdest = prowdest; + + for (b=0; b> 16) & 63; + t = (((i << 16) + turb[j & (CYCLE-1)]) >> 16) & 63; + *pd++ = *(pbasetex + (t<<6) + s); + } + } +} + + +/* +================ +R_GenTurbTile16 +================ +*/ +void R_GenTurbTile16 (pixel_t *pbasetex, void *pdest) +{ + int *turb; + int i, j, s, t; + unsigned short *pd; + + turb = sintable + ((int)(cl.time*SPEED)&(CYCLE-1)); + pd = (unsigned short *)pdest; + + for (i=0 ; i> 16) & 63; + t = (((i << 16) + turb[j & (CYCLE-1)]) >> 16) & 63; + *pd++ = d_8to16table[*(pbasetex + (t<<6) + s)]; + } + } +} + + +/* +================ +R_GenTile +================ +*/ +void R_GenTile (msurface_t *psurf, void *pdest) +{ + if (psurf->flags & SURF_DRAWTURB) + { + if (r_pixbytes == 1) + { + R_GenTurbTile ((pixel_t *) + ((byte *)psurf->texinfo->texture + psurf->texinfo->texture->offsets[0]), pdest); + } + else + { + R_GenTurbTile16 ((pixel_t *) + ((byte *)psurf->texinfo->texture + psurf->texinfo->texture->offsets[0]), pdest); + } + } + else if (psurf->flags & SURF_DRAWSKY) + { + if (r_pixbytes == 1) + { + R_GenSkyTile (pdest); + } + else + { + R_GenSkyTile16 (pdest); + } + } + else + { + Sys_Error ("Unknown tile type"); + } +} + diff --git a/project/jni/application/quake/source/r_vars.c b/project/jni/application/quake/source/r_vars.c new file mode 100644 index 000000000..90fe7f558 --- /dev/null +++ b/project/jni/application/quake/source/r_vars.c @@ -0,0 +1,39 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// r_vars.c: global refresh variables + +#include "quakedef.h" + +#if !id386 + +// all global and static refresh variables are collected in a contiguous block +// to avoid cache conflicts. + +//------------------------------------------------------- +// global refresh variables +//------------------------------------------------------- + +// FIXME: make into one big structure, like cl or sv +// FIXME: do separately for refresh engine and driver + +int r_bmodelactive; + +#endif // !id386 + diff --git a/project/jni/application/quake/source/render.h b/project/jni/application/quake/source/render.h new file mode 100644 index 000000000..46be082ce --- /dev/null +++ b/project/jni/application/quake/source/render.h @@ -0,0 +1,257 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// refresh.h -- public interface to refresh functions + +#define MAXCLIPPLANES 11 + +#define TOP_RANGE 16 // soldier uniform colors +#define BOTTOM_RANGE 96 + +//============================================================================= + +typedef struct efrag_s +{ + struct mleaf_s *leaf; + struct efrag_s *leafnext; + struct entity_s *entity; + struct efrag_s *entnext; +} efrag_t; + +typedef struct efrag_FPM_s +{ + struct mleaf_FPM_s *leaf; + struct efrag_FPM_s *leafnext; + struct entity_FPM_s *entity; + struct efrag_FPM_s *entnext; +} efrag_FPM_t; + + +typedef struct entity_s +{ + qboolean forcelink; // model changed + + int update_type; + + entity_state_t baseline; // to fill in defaults in updates + + double msgtime; // time of last update + vec3_t msg_origins[2]; // last two updates (0 is newest) + vec3_t origin; + vec3_t msg_angles[2]; // last two updates (0 is newest) + vec3_t angles; + struct model_s *model; // NULL = no model + struct efrag_s *efrag; // linked list of efrags + int frame; + float syncbase; // for client-side animations + byte *colormap; + int effects; // light, particals, etc + int skinnum; // for Alias models + int visframe; // last frame this entity was + // found in an active leaf + + int dlightframe; // dynamic lighting + int dlightbits; + +// FIXME: could turn these into a union + int trivial_accept; + struct mnode_s *topnode; // for bmodels, first world node + // that splits bmodel, or NULL if + // not split +} entity_t; + +typedef struct entity_FPM_s +{ + qboolean forcelink; // model changed + + int update_type; + + entity_state_FPM_t baseline; // to fill in defaults in updates + + double msgtime; // time of last update + vec3_FPM_t msg_origins[2]; // last two updates (0 is newest) + vec3_FPM_t origin; + vec3_FPM_t msg_angles[2]; // last two updates (0 is newest) + vec3_FPM_t angles; + struct model_FPM_s *model; // NULL = no model + struct efrag_FPM_s *efrag; // linked list of efrags + int frame; + float syncbase; // for client-side animations + byte *colormap; + int effects; // light, particals, etc + int skinnum; // for Alias models + int visframe; // last frame this entity was + // found in an active leaf + + int dlightframe; // dynamic lighting + int dlightbits; + +// FIXME: could turn these into a union + int trivial_accept; + struct mnode_FPM_s *topnode; // for bmodels, first world node + // that splits bmodel, or NULL if + // not split +} entity_FPM_t; + +// !!! if this is changed, it must be changed in asm_draw.h too !!! +typedef struct +{ + vrect_t vrect; // subwindow in video for refresh + // FIXME: not need vrect next field here? + vrect_t aliasvrect; // scaled Alias version + int vrectright, vrectbottom; // right & bottom screen coords + int aliasvrectright, aliasvrectbottom; // scaled Alias versions + float vrectrightedge; // rightmost right edge we care about, + // for use in edge list + float fvrectx, fvrecty; // for floating-point compares + float fvrectx_adj, fvrecty_adj; // left and top edges, for clamping + int vrect_x_adj_shift20; // (vrect.x + 0.5 - epsilon) << 20 + int vrectright_adj_shift20; // (vrectright + 0.5 - epsilon) << 20 + float fvrectright_adj, fvrectbottom_adj; + // right and bottom edges, for clamping + float fvrectright; // rightmost edge, for Alias clamping + float fvrectbottom; // bottommost edge, for Alias clamping + float horizontalFieldOfView; // at Z = 1.0, this many X is visible + // 2.0 = 90 degrees + float xOrigin; // should probably allways be 0.5 + float yOrigin; // between be around 0.3 to 0.5 + + vec3_t vieworg; + vec3_t viewangles; + + float fov_x, fov_y; + + int ambientlight; +} refdef_t; + +typedef struct +{ + vrect_t vrect; // subwindow in video for refresh + // FIXME: not need vrect next field here? + vrect_t aliasvrect; // scaled Alias version + int vrectright, vrectbottom; // right & bottom screen coords + int aliasvrectright, aliasvrectbottom; // scaled Alias versions + fixedpoint_t vrectrightedge; // rightmost right edge we care about, + // for use in edge list + fixedpoint_t fvrectx, fvrecty; // for floating-point compares + fixedpoint_t fvrectx_adj, fvrecty_adj; // left and top edges, for clamping + int vrect_x_adj_shift20; // (vrect.x + 0.5 - epsilon) << 20 + int vrectright_adj_shift20; // (vrectright + 0.5 - epsilon) << 20 + fixedpoint_t fvrectright_adj, fvrectbottom_adj; + // right and bottom edges, for clamping + fixedpoint_t fvrectright; // rightmost edge, for Alias clamping + fixedpoint_t fvrectbottom; // bottommost edge, for Alias clamping + fixedpoint_t horizontalFieldOfView; // at Z = 1.0, this many X is visible + // 2.0 = 90 degrees + fixedpoint_t xOrigin; // should probably allways be 0.5 + fixedpoint_t yOrigin; // between be around 0.3 to 0.5 + + vec3_FPM_t vieworg; + vec3_FPM_t viewangles; + + fixedpoint_t fov_x, fov_y; + + int ambientlight; +} refdef_FPM_t; + + +// +// refresh +// +extern int reinit_surfcache; + + +extern refdef_t r_refdef; +extern refdef_FPM_t r_refdefFPM; + +extern vec3_t r_origin, vpn, vright, vup; + +#ifdef USE_PQ_OPT1 +extern int vpn_fxp[3], vright_fxp[3], vup_fxp[3]; +extern int xscale_fxp, yscale_fxp, xcenter_fxp, ycenter_fxp; +extern int r_refdef_fvrectx_adj_fxp; +extern int r_refdef_fvrectright_adj_fxp; +extern int r_refdef_fvrecty_adj_fxp; +extern int r_refdef_fvrectbottom_adj_fxp; +#endif + +extern vec3_FPM_t r_originFPM, vpnFPM, vrightFPM, vupFPM; + +extern struct texture_s *r_notexture_mip; + + +void R_Init (void); +void R_InitFPM (void); +void R_InitTextures (void); +void R_InitEfrags (void); +void R_RenderView (void); // must set r_refdef first +void R_RenderViewFPM (void); // must set r_refdefFPM first +void R_ViewChanged (vrect_t *pvrect, int lineadj, float aspect); +void R_ViewChangedFPM (vrect_t *pvrect, int lineadj, fixedpoint_t aspect); + // called whenever r_refdef or vid change +void R_InitSky (struct texture_s *mt); // called at level load + +void R_AddEfrags (entity_t *ent); +void R_AddEfragsFPM (entity_FPM_t *ent); +void R_RemoveEfrags (entity_t *ent); +void R_RemoveEfragsFPM (entity_FPM_t *ent); + +void R_NewMap (void); +void R_NewMapFPM (void); + +void R_ParseParticleEffect (void); +void R_ParseParticleEffectFPM (void); +void R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count); +void R_RunParticleEffectFPM (vec3_FPM_t org, vec3_FPM_t dir, int color, int count); +void R_RocketTrail (vec3_t start, vec3_t end, int type); +void R_RocketTrailFPM (vec3_FPM_t start, vec3_FPM_t end, int type); + +#ifdef QUAKE2 +void R_DarkFieldParticles (entity_t *ent); +#endif +void R_EntityParticles (entity_t *ent); +void R_EntityParticlesFPM (entity_FPM_t *ent); +void R_BlobExplosion (vec3_t org); +void R_BlobExplosionFPM (vec3_FPM_t org); +void R_ParticleExplosion (vec3_t org); +void R_ParticleExplosionFPM (vec3_FPM_t org); +void R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength); +void R_ParticleExplosion2FPM (vec3_FPM_t org, int colorStart, int colorLength); +void R_LavaSplash (vec3_t org); +void R_LavaSplashFPM (vec3_FPM_t org); +void R_TeleportSplash (vec3_t org); +void R_TeleportSplashFPM (vec3_FPM_t org); + +void R_PushDlights (void); +void R_PushDlightsFPM (void); + +// +// surface cache related +// +extern int reinit_surfcache; // if 1, surface cache is currently empty and +extern qboolean r_cache_thrash; // set if thrashing the surface cache + +int D_SurfaceCacheForRes (int width, int height); +void D_FlushCaches (void); +void D_FlushCachesFPM (void); +void D_DeleteSurfaceCache (void); +void D_InitCaches (void *buffer, int size); +void R_SetVrect (vrect_t *pvrect, vrect_t *pvrectin, int lineadj); +void R_SetVrectFPM (vrect_t *pvrect, vrect_t *pvrectin, int lineadj); diff --git a/project/jni/application/quake/source/sbar.c b/project/jni/application/quake/source/sbar.c new file mode 100644 index 000000000..2c955c652 --- /dev/null +++ b/project/jni/application/quake/source/sbar.c @@ -0,0 +1,2190 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sbar.c -- status bar code + +#include "quakedef.h" + +//Dan East: +extern int min_vid_width; + +int sb_updates; // if >= vid.numpages, no update needed + +#define STAT_MINUS 10 // num frame for '-' stats digit +qpic_t *sb_nums[2][11]; +qpic_t *sb_colon, *sb_slash; +qpic_t *sb_ibar; +qpic_t *sb_sbar; +qpic_t *sb_scorebar; + +qpic_t *sb_weapons[7][8]; // 0 is active, 1 is owned, 2-5 are flashes +qpic_t *sb_ammo[4]; +qpic_t *sb_sigil[4]; +qpic_t *sb_armor[3]; +qpic_t *sb_items[32]; + +qpic_t *sb_faces[7][2]; // 0 is gibbed, 1 is dead, 2-6 are alive + // 0 is static, 1 is temporary animation +qpic_t *sb_face_invis; +qpic_t *sb_face_quad; +qpic_t *sb_face_invuln; +qpic_t *sb_face_invis_invuln; + +qboolean sb_showscores; + +int sb_lines; // scan lines to draw + +qpic_t *rsb_invbar[2]; +qpic_t *rsb_weapons[5]; +qpic_t *rsb_items[2]; +qpic_t *rsb_ammo[3]; +qpic_t *rsb_teambord; // PGM 01/19/97 - team color border + +//MED 01/04/97 added two more weapons + 3 alternates for grenade launcher +qpic_t *hsb_weapons[7][5]; // 0 is active, 1 is owned, 2-5 are flashes +//MED 01/04/97 added array to simplify weapon parsing +int hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT}; +//MED 01/04/97 added hipnotic items array +qpic_t *hsb_items[2]; + +void Sbar_MiniDeathmatchOverlay (void); +void Sbar_DeathmatchOverlay (void); +void M_DrawPic (int x, int y, qpic_t *pic); + +#ifdef USEFPM +void Sbar_MiniDeathmatchOverlayFPM (void); +void Sbar_DeathmatchOverlayFPM (void); +#endif //USEFPM +/* +=============== +Sbar_ShowScores + +Tab key down +=============== +*/ +void Sbar_ShowScores (void) +{ + if (sb_showscores) + return; + sb_showscores = true; + sb_updates = 0; +} + +/* +=============== +Sbar_DontShowScores + +Tab key up +=============== +*/ +void Sbar_DontShowScores (void) +{ + sb_showscores = false; + sb_updates = 0; +} + +/* +=============== +Sbar_Changed +=============== +*/ +void Sbar_Changed (void) +{ + sb_updates = 0; // update next frame +} + +/* +=============== +Sbar_Init +=============== +*/ +void Sbar_Init (void) +{ + int i; + + for (i=0 ; i<10 ; i++) + { + sb_nums[0][i] = Draw_PicFromWad (va("num_%i",i)); + sb_nums[1][i] = Draw_PicFromWad (va("anum_%i",i)); + } + + sb_nums[0][10] = Draw_PicFromWad ("num_minus"); + sb_nums[1][10] = Draw_PicFromWad ("anum_minus"); + + sb_colon = Draw_PicFromWad ("num_colon"); + sb_slash = Draw_PicFromWad ("num_slash"); + + sb_weapons[0][0] = Draw_PicFromWad ("inv_shotgun"); + sb_weapons[0][1] = Draw_PicFromWad ("inv_sshotgun"); + sb_weapons[0][2] = Draw_PicFromWad ("inv_nailgun"); + sb_weapons[0][3] = Draw_PicFromWad ("inv_snailgun"); + sb_weapons[0][4] = Draw_PicFromWad ("inv_rlaunch"); + sb_weapons[0][5] = Draw_PicFromWad ("inv_srlaunch"); + sb_weapons[0][6] = Draw_PicFromWad ("inv_lightng"); + + sb_weapons[1][0] = Draw_PicFromWad ("inv2_shotgun"); + sb_weapons[1][1] = Draw_PicFromWad ("inv2_sshotgun"); + sb_weapons[1][2] = Draw_PicFromWad ("inv2_nailgun"); + sb_weapons[1][3] = Draw_PicFromWad ("inv2_snailgun"); + sb_weapons[1][4] = Draw_PicFromWad ("inv2_rlaunch"); + sb_weapons[1][5] = Draw_PicFromWad ("inv2_srlaunch"); + sb_weapons[1][6] = Draw_PicFromWad ("inv2_lightng"); + + for (i=0 ; i<5 ; i++) + { + sb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_shotgun",i+1)); + sb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_sshotgun",i+1)); + sb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_nailgun",i+1)); + sb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_snailgun",i+1)); + sb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_rlaunch",i+1)); + sb_weapons[2+i][5] = Draw_PicFromWad (va("inva%i_srlaunch",i+1)); + sb_weapons[2+i][6] = Draw_PicFromWad (va("inva%i_lightng",i+1)); + } + + sb_ammo[0] = Draw_PicFromWad ("sb_shells"); + sb_ammo[1] = Draw_PicFromWad ("sb_nails"); + sb_ammo[2] = Draw_PicFromWad ("sb_rocket"); + sb_ammo[3] = Draw_PicFromWad ("sb_cells"); + + sb_armor[0] = Draw_PicFromWad ("sb_armor1"); + sb_armor[1] = Draw_PicFromWad ("sb_armor2"); + sb_armor[2] = Draw_PicFromWad ("sb_armor3"); + + sb_items[0] = Draw_PicFromWad ("sb_key1"); + sb_items[1] = Draw_PicFromWad ("sb_key2"); + sb_items[2] = Draw_PicFromWad ("sb_invis"); + sb_items[3] = Draw_PicFromWad ("sb_invuln"); + sb_items[4] = Draw_PicFromWad ("sb_suit"); + sb_items[5] = Draw_PicFromWad ("sb_quad"); + + sb_sigil[0] = Draw_PicFromWad ("sb_sigil1"); + sb_sigil[1] = Draw_PicFromWad ("sb_sigil2"); + sb_sigil[2] = Draw_PicFromWad ("sb_sigil3"); + sb_sigil[3] = Draw_PicFromWad ("sb_sigil4"); + + sb_faces[4][0] = Draw_PicFromWad ("face1"); + sb_faces[4][1] = Draw_PicFromWad ("face_p1"); + sb_faces[3][0] = Draw_PicFromWad ("face2"); + sb_faces[3][1] = Draw_PicFromWad ("face_p2"); + sb_faces[2][0] = Draw_PicFromWad ("face3"); + sb_faces[2][1] = Draw_PicFromWad ("face_p3"); + sb_faces[1][0] = Draw_PicFromWad ("face4"); + sb_faces[1][1] = Draw_PicFromWad ("face_p4"); + sb_faces[0][0] = Draw_PicFromWad ("face5"); + sb_faces[0][1] = Draw_PicFromWad ("face_p5"); + + sb_face_invis = Draw_PicFromWad ("face_invis"); + sb_face_invuln = Draw_PicFromWad ("face_invul2"); + sb_face_invis_invuln = Draw_PicFromWad ("face_inv2"); + sb_face_quad = Draw_PicFromWad ("face_quad"); + + Cmd_AddCommand ("+showscores", Sbar_ShowScores); + Cmd_AddCommand ("-showscores", Sbar_DontShowScores); + + sb_sbar = Draw_PicFromWad ("sbar"); + sb_ibar = Draw_PicFromWad ("ibar"); + sb_scorebar = Draw_PicFromWad ("scorebar"); + +//MED 01/04/97 added new hipnotic weapons + if (r2_mod == 1) + { + hsb_weapons[0][0] = Draw_PicFromWad ("inv_laser"); + hsb_weapons[0][1] = Draw_PicFromWad ("inv_mjolnir"); + hsb_weapons[0][2] = Draw_PicFromWad ("inv_gren_prox"); + hsb_weapons[0][3] = Draw_PicFromWad ("inv_prox_gren"); + hsb_weapons[0][4] = Draw_PicFromWad ("inv_prox"); + + hsb_weapons[1][0] = Draw_PicFromWad ("inv2_laser"); + hsb_weapons[1][1] = Draw_PicFromWad ("inv2_mjolnir"); + hsb_weapons[1][2] = Draw_PicFromWad ("inv2_gren_prox"); + hsb_weapons[1][3] = Draw_PicFromWad ("inv2_prox_gren"); + hsb_weapons[1][4] = Draw_PicFromWad ("inv2_prox"); + + for (i=0 ; i<5 ; i++) + { + hsb_weapons[2+i][0] = Draw_PicFromWad (va("inva%i_laser",i+1)); + hsb_weapons[2+i][1] = Draw_PicFromWad (va("inva%i_mjolnir",i+1)); + hsb_weapons[2+i][2] = Draw_PicFromWad (va("inva%i_gren_prox",i+1)); + hsb_weapons[2+i][3] = Draw_PicFromWad (va("inva%i_prox_gren",i+1)); + hsb_weapons[2+i][4] = Draw_PicFromWad (va("inva%i_prox",i+1)); + } + + hsb_items[0] = Draw_PicFromWad ("sb_wsuit"); + hsb_items[1] = Draw_PicFromWad ("sb_eshld"); + } + + if (r2_mod == 2) + { + rsb_invbar[0] = Draw_PicFromWad ("r_invbar1"); + rsb_invbar[1] = Draw_PicFromWad ("r_invbar2"); + + rsb_weapons[0] = Draw_PicFromWad ("r_lava"); + rsb_weapons[1] = Draw_PicFromWad ("r_superlava"); + rsb_weapons[2] = Draw_PicFromWad ("r_gren"); + rsb_weapons[3] = Draw_PicFromWad ("r_multirock"); + rsb_weapons[4] = Draw_PicFromWad ("r_plasma"); + + rsb_items[0] = Draw_PicFromWad ("r_shield1"); + rsb_items[1] = Draw_PicFromWad ("r_agrav1"); + +// PGM 01/19/97 - team color border + rsb_teambord = Draw_PicFromWad ("r_teambord"); +// PGM 01/19/97 - team color border + + rsb_ammo[0] = Draw_PicFromWad ("r_ammolava"); + rsb_ammo[1] = Draw_PicFromWad ("r_ammomulti"); + rsb_ammo[2] = Draw_PicFromWad ("r_ammoplasma"); + } +} + + +//============================================================================= + +// drawing routines are relative to the status bar location + +/* +============= +Sbar_DrawPic +============= +*/ +void Sbar_DrawPic (int x, int y, qpic_t *pic) +{ + if (cl.gametype == GAME_DEATHMATCH) + Draw_Pic (x /* + ((vid.width - 320)>>1)*/, y + (vid.height-SBAR_HEIGHT), pic); + else + Draw_Pic (x + ((vid.width - min_vid_width/*320*/)>>1), y + (vid.height-SBAR_HEIGHT), pic); +} + +#ifdef USEFPM +void Sbar_DrawPicFPM (int x, int y, qpic_t *pic) +{ + if (clFPM.gametype == GAME_DEATHMATCH) + Draw_Pic (x /* + ((vid.width - 320)>>1)*/, y + (vid.height-SBAR_HEIGHT), pic); + else + Draw_Pic (x + ((vid.width - min_vid_width/*320*/)>>1), y + (vid.height-SBAR_HEIGHT), pic); +} +#endif //USEFPM + +/* +============= +Sbar_DrawTransPic +============= +*/ +void Sbar_DrawTransPic (int x, int y, qpic_t *pic) +{ + if (cl.gametype == GAME_DEATHMATCH) + Draw_TransPic (x /*+ ((vid.width - 320)>>1)*/, y + (vid.height-SBAR_HEIGHT), pic); + else + //Dan: + Draw_TransPic (x + ((vid.width - min_vid_width/*320*/)>>1), y + (vid.height-SBAR_HEIGHT), pic); +} + +#ifdef USEFPM +void Sbar_DrawTransPicFPM (int x, int y, qpic_t *pic) +{ + if (clFPM.gametype == GAME_DEATHMATCH) + Draw_TransPic (x /*+ ((vid.width - 320)>>1)*/, y + (vid.height-SBAR_HEIGHT), pic); + else + //Dan: + Draw_TransPic (x + ((vid.width - min_vid_width/*320*/)>>1), y + (vid.height-SBAR_HEIGHT), pic); +} +#endif //USEFPM +/* +================ +Sbar_DrawCharacter + +Draws one solid graphics character +================ +*/ +void Sbar_DrawCharacter (int x, int y, int num) +{ + if (cl.gametype == GAME_DEATHMATCH) + Draw_Character ( x /*+ ((vid.width - 320)>>1) */ + 4 , y + vid.height-SBAR_HEIGHT, num); + else + //Dan: + Draw_Character ( x + ((vid.width - min_vid_width/*320*/)>>1) + 4 , y + vid.height-SBAR_HEIGHT, num); +} + +#ifdef USEFPM +void Sbar_DrawCharacterFPM (int x, int y, int num) +{ + if (clFPM.gametype == GAME_DEATHMATCH) + Draw_Character ( x /*+ ((vid.width - 320)>>1) */ + 4 , y + vid.height-SBAR_HEIGHT, num); + else + //Dan: + Draw_Character ( x + ((vid.width - min_vid_width/*320*/)>>1) + 4 , y + vid.height-SBAR_HEIGHT, num); +} +#endif //USEFPM +/* +================ +Sbar_DrawString +================ +*/ +void Sbar_DrawString (int x, int y, char *str) +{ + if (cl.gametype == GAME_DEATHMATCH) + Draw_String (x /*+ ((vid.width - 320)>>1)*/, y+ vid.height-SBAR_HEIGHT, str); + else + Draw_String (x + ((vid.width - min_vid_width/*320*/)>>1), y+ vid.height-SBAR_HEIGHT, str); +} + +#ifdef USEFPM +void Sbar_DrawStringFPM (int x, int y, char *str) +{ + if (clFPM.gametype == GAME_DEATHMATCH) + Draw_String (x /*+ ((vid.width - 320)>>1)*/, y+ vid.height-SBAR_HEIGHT, str); + else + Draw_String (x + ((vid.width - min_vid_width/*320*/)>>1), y+ vid.height-SBAR_HEIGHT, str); +} +#endif //USEFPM +/* +============= +Sbar_itoa +============= +*/ +int Sbar_itoa (int num, char *buf) +{ + char *str; + int pow10; + int dig; + + str = buf; + + if (num < 0) + { + *str++ = '-'; + num = -num; + } + + for (pow10 = 10 ; num >= pow10 ; pow10 *= 10) + ; + + do + { + pow10 /= 10; + dig = num/pow10; + *str++ = '0'+dig; + num -= dig*pow10; + } while (pow10 != 1); + + *str = 0; + + return str-buf; +} + + +/* +============= +Sbar_DrawNum +============= +*/ +void Sbar_DrawNum (int x, int y, int num, int digits, int color) +{ + char str[12]; + char *ptr; + int l, frame; + + l = Sbar_itoa (num, str); + ptr = str; + if (l > digits) + ptr += (l-digits); + if (l < digits) + x += (digits-l)*24; + + while (*ptr) + { + if (*ptr == '-') + frame = STAT_MINUS; + else + frame = *ptr -'0'; + + Sbar_DrawTransPic (x,y,sb_nums[color][frame]); + x += 24; + ptr++; + } +} + +#ifdef USEFPM +void Sbar_DrawNumFPM (int x, int y, int num, int digits, int color) +{ + char str[12]; + char *ptr; + int l, frame; + + l = Sbar_itoa (num, str); + ptr = str; + if (l > digits) + ptr += (l-digits); + if (l < digits) + x += (digits-l)*24; + + while (*ptr) + { + if (*ptr == '-') + frame = STAT_MINUS; + else + frame = *ptr -'0'; + + Sbar_DrawTransPicFPM (x,y,sb_nums[color][frame]); + x += 24; + ptr++; + } +} +#endif //USEFPM + +//============================================================================= + +int fragsort[MAX_SCOREBOARD]; + +char scoreboardtext[MAX_SCOREBOARD][20]; +int scoreboardtop[MAX_SCOREBOARD]; +int scoreboardbottom[MAX_SCOREBOARD]; +int scoreboardcount[MAX_SCOREBOARD]; +int scoreboardlines; + +/* +=============== +Sbar_SortFrags +=============== +*/ +void Sbar_SortFrags (void) +{ + int i, j, k; + +// sort by frags + scoreboardlines = 0; + for (i=0 ; ifrags, s->name); + + top = s->colors & 0xf0; + bottom = (s->colors & 15) <<4; + scoreboardtop[i] = Sbar_ColorForMap (top); + scoreboardbottom[i] = Sbar_ColorForMap (bottom); + } +} + + + +/* +=============== +Sbar_SoloScoreboard +=============== +*/ +void Sbar_SoloScoreboard (void) +{ + char str[80]; + int minutes, seconds, tens, units; + int l; + + sprintf (str,"Monsters:%3i /%3i", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]); + Sbar_DrawString (8, 4, str); + + sprintf (str,"Secrets :%3i /%3i", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]); + Sbar_DrawString (8, 12, str); + +// time + minutes = (int) (cl.time / 60); + seconds = (int) (cl.time - 60*minutes); + tens = seconds / 10; + units = seconds - 10*tens; + sprintf (str,"Time :%3i:%i%i", minutes, tens, units); + Sbar_DrawString (184, 4, str); + +// draw level name + l = strlen (cl.levelname); + Sbar_DrawString (232 - l*4, 12, cl.levelname); +} + +#ifdef USEFPM +void Sbar_SoloScoreboardFPM (void) +{ + char str[80]; + int minutes, seconds, tens, units; + int l; + + sprintf (str,"Monsters:%3i /%3i", clFPM.stats[STAT_MONSTERS], clFPM.stats[STAT_TOTALMONSTERS]); + Sbar_DrawString (8, 4, str); + + sprintf (str,"Secrets :%3i /%3i", clFPM.stats[STAT_SECRETS], clFPM.stats[STAT_TOTALSECRETS]); + Sbar_DrawString (8, 12, str); + +// time + minutes = (int) (clFPM.time / 60); + seconds = (int) (clFPM.time - 60*minutes); + tens = seconds / 10; + units = seconds - 10*tens; + sprintf (str,"Time :%3i:%i%i", minutes, tens, units); + Sbar_DrawString (184, 4, str); + +// draw level name + l = strlen (clFPM.levelname); + Sbar_DrawString (232 - l*4, 12, clFPM.levelname); +} +#endif //USEFPM + +/* +=============== +Sbar_DrawScoreboard +=============== +*/ +void Sbar_DrawScoreboard (void) +{ + Sbar_SoloScoreboard (); + if (cl.gametype == GAME_DEATHMATCH) + Sbar_DeathmatchOverlay (); +#if 0 + int i, j, c; + int x, y; + int l; + int top, bottom; + scoreboard_t *s; + + if (cl.gametype != GAME_DEATHMATCH) + { + Sbar_SoloScoreboard (); + return; + } + + Sbar_UpdateScoreboard (); + + l = scoreboardlines <= 6 ? scoreboardlines : 6; + + for (i=0 ; iname[0]) + continue; + + // draw background + top = s->colors & 0xf0; + bottom = (s->colors & 15)<<4; + top = Sbar_ColorForMap (top); + bottom = Sbar_ColorForMap (bottom); + + Draw_Fill ( x*8+10 + ((vid.width - min_vid_width/*320*/)>>1), y + vid.height - SBAR_HEIGHT, 28, 4, top); + Draw_Fill ( x*8+10 + ((vid.width - min_vid_width/*320*/)>>1), y+4 + vid.height - SBAR_HEIGHT, 28, 4, bottom); + + // draw text + for (j=0 ; j<20 ; j++) + { + c = scoreboardtext[i][j]; + if (c == 0 || c == ' ') + continue; + Sbar_DrawCharacter ( (x+j)*8, y, c); + } + } +#endif +} + +#ifdef USEFPM +void Sbar_DrawScoreboardFPM (void) +{ + Sbar_SoloScoreboardFPM (); + if (clFPM.gametype == GAME_DEATHMATCH) + Sbar_DeathmatchOverlay (); +} +#endif //USEFPM + +//============================================================================= + +/* +=============== +Sbar_DrawInventory +=============== +*/ +void Sbar_DrawInventory (void) +{ + int i; + char num[6]; + float time; + int flashon; + + if (r2_mod == 2) + { + if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN ) + Sbar_DrawPic (0, -24, rsb_invbar[0]); + else + Sbar_DrawPic (0, -24, rsb_invbar[1]); + } + else + { + Sbar_DrawPic (0, -24, sb_ibar); + } + +// weapons + for (i=0 ; i<7 ; i++) + { + if (cl.items & (IT_SHOTGUN<= 10) + { + if ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN< 1) + sb_updates = 0; // force update to remove flash + } + } + +// MED 01/04/97 +// hipnotic weapons + if (r2_mod == 1) + { + int grenadeflashing=0; + for (i=0 ; i<4 ; i++) + { + if (cl.items & (1<= 10) + { + if ( cl.stats[STAT_ACTIVEWEAPON] == (1< 1) + sb_updates = 0; // force update to remove flash + } + } + } + + if (r2_mod == 2) + { + // check for powered up weapon. + if ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN ) + { + for (i=0;i<5;i++) + { + if (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i)) + { + Sbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]); + } + } + } + } + +// ammo counts + for (i=0 ; i<4 ; i++) + { + sprintf (num, "%3i",cl.stats[STAT_SHELLS+i] ); + if (num[0] != ' ') + Sbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0'); + if (num[1] != ' ') + Sbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0'); + if (num[2] != ' ') + Sbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0'); + } + + flashon = 0; + // items + for (i=0 ; i<6 ; i++) + if (cl.items & (1<<(17+i))) + { + time = cl.item_gettime[17+i]; + if (time && time > cl.time - 2 && flashon ) + { // flash frame + sb_updates = 0; + } + else + { + //MED 01/04/97 changed keys + if (!hipnotic || (i>1)) + { + Sbar_DrawPic (192 + i*16, -16, sb_items[i]); + } + } + if (time && time > cl.time - 2) + sb_updates = 0; + } + //MED 01/04/97 added hipnotic items + // hipnotic items + if (r2_mod == 1) + { + for (i=0 ; i<2 ; i++) + if (cl.items & (1<<(24+i))) + { + time = cl.item_gettime[24+i]; + if (time && time > cl.time - 2 && flashon ) + { // flash frame + sb_updates = 0; + } + else + { + Sbar_DrawPic (288 + i*16, -16, hsb_items[i]); + } + if (time && time > cl.time - 2) + sb_updates = 0; + } + } + + if (r2_mod == 2) + { + // new rogue items + for (i=0 ; i<2 ; i++) + { + if (cl.items & (1<<(29+i))) + { + time = cl.item_gettime[29+i]; + + if (time && time > cl.time - 2 && flashon ) + { // flash frame + sb_updates = 0; + } + else + { + Sbar_DrawPic (288 + i*16, -16, rsb_items[i]); + } + + if (time && time > cl.time - 2) + sb_updates = 0; + } + } + } + else + { + // sigils + for (i=0 ; i<4 ; i++) + { + if (cl.items & (1<<(28+i))) + { + time = cl.item_gettime[28+i]; + if (time && time > cl.time - 2 && flashon ) + { // flash frame + sb_updates = 0; + } + else + Sbar_DrawPic (min_vid_width/*320*/-32 + i*8, -16, sb_sigil[i]); + if (time && time > cl.time - 2) + sb_updates = 0; + } + } + } +} + +#ifdef USEFPM +void Sbar_DrawInventoryFPM (void) +{ + int i; + char num[6]; + float time; + int flashon; + + if (r2_mod == 2) + { + if ( clFPM.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN ) + Sbar_DrawPicFPM (0, -24, rsb_invbar[0]); + else + Sbar_DrawPicFPM (0, -24, rsb_invbar[1]); + } + else + { + Sbar_DrawPicFPM (0, -24, sb_ibar); + } + +// weapons + for (i=0 ; i<7 ; i++) + { + if (clFPM.items & (IT_SHOTGUN<= 10) + { + if ( clFPM.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN< 1) + sb_updates = 0; // force update to remove flash + } + } + +// MED 01/04/97 +// hipnotic weapons + if (r2_mod == 1) + { + int grenadeflashing=0; + for (i=0 ; i<4 ; i++) + { + if (clFPM.items & (1<= 10) + { + if ( clFPM.stats[STAT_ACTIVEWEAPON] == (1< 1) + sb_updates = 0; // force update to remove flash + } + } + } + + if (r2_mod == 2) + { + // check for powered up weapon. + if ( clFPM.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN ) + { + for (i=0;i<5;i++) + { + if (clFPM.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i)) + { + Sbar_DrawPicFPM ((i+2)*24, -16, rsb_weapons[i]); + } + } + } + } + +// ammo counts + for (i=0 ; i<4 ; i++) + { + sprintf (num, "%3i",clFPM.stats[STAT_SHELLS+i] ); + if (num[0] != ' ') + Sbar_DrawCharacterFPM ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0'); + if (num[1] != ' ') + Sbar_DrawCharacterFPM ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0'); + if (num[2] != ' ') + Sbar_DrawCharacterFPM ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0'); + } + + flashon = 0; + // items + for (i=0 ; i<6 ; i++) + if (clFPM.items & (1<<(17+i))) + { + time = clFPM.item_gettime[17+i]; + if (time && time > clFPM.time - 2 && flashon ) + { // flash frame + sb_updates = 0; + } + else + { + //MED 01/04/97 changed keys + if (!hipnotic || (i>1)) + { + Sbar_DrawPicFPM (192 + i*16, -16, sb_items[i]); + } + } + if (time && time > clFPM.time - 2) + sb_updates = 0; + } + //MED 01/04/97 added hipnotic items + // hipnotic items + if (r2_mod == 1) + { + for (i=0 ; i<2 ; i++) + if (clFPM.items & (1<<(24+i))) + { + time = clFPM.item_gettime[24+i]; + if (time && time > clFPM.time - 2 && flashon ) + { // flash frame + sb_updates = 0; + } + else + { + Sbar_DrawPicFPM (288 + i*16, -16, hsb_items[i]); + } + if (time && time > clFPM.time - 2) + sb_updates = 0; + } + } + + if (r2_mod == 2) + { + // new rogue items + for (i=0 ; i<2 ; i++) + { + if (clFPM.items & (1<<(29+i))) + { + time = clFPM.item_gettime[29+i]; + + if (time && time > clFPM.time - 2 && flashon ) + { // flash frame + sb_updates = 0; + } + else + { + Sbar_DrawPicFPM (288 + i*16, -16, rsb_items[i]); + } + + if (time && time > clFPM.time - 2) + sb_updates = 0; + } + } + } + else + { + // sigils + for (i=0 ; i<4 ; i++) + { + if (clFPM.items & (1<<(28+i))) + { + time = clFPM.item_gettime[28+i]; + if (time && time > clFPM.time - 2 && flashon ) + { // flash frame + sb_updates = 0; + } + else + Sbar_DrawPicFPM (min_vid_width/*320*/-32 + i*8, -16, sb_sigil[i]); + if (time && time > clFPM.time - 2) + sb_updates = 0; + } + } + } +} +#endif //USEFPM + +//============================================================================= + +/* +=============== +Sbar_DrawFrags +=============== +*/ +void Sbar_DrawFrags (void) +{ + int i, k, l; + int top, bottom; + int x, y, f; + int xofs; + char num[12]; + scoreboard_t *s; + + Sbar_SortFrags (); + +// draw the text + l = scoreboardlines <= 4 ? scoreboardlines : 4; + + x = 23; + if (cl.gametype == GAME_DEATHMATCH) + xofs = 0; + else + xofs = (vid.width - min_vid_width/*320*/)>>1; + y = vid.height - SBAR_HEIGHT - 23; + + for (i=0 ; iname[0]) + continue; + + // draw background + top = s->colors & 0xf0; + bottom = (s->colors & 15)<<4; + top = Sbar_ColorForMap (top); + bottom = Sbar_ColorForMap (bottom); + + Draw_Fill (xofs + x*8 + 10, y, 28, 4, top); + Draw_Fill (xofs + x*8 + 10, y+4, 28, 3, bottom); + + // draw number + f = s->frags; + sprintf (num, "%3i",f); + + Sbar_DrawCharacter ( (x+1)*8 , -24, num[0]); + Sbar_DrawCharacter ( (x+2)*8 , -24, num[1]); + Sbar_DrawCharacter ( (x+3)*8 , -24, num[2]); + + if (k == cl.viewentity - 1) + { + Sbar_DrawCharacter (x*8+2, -24, 16); + Sbar_DrawCharacter ( (x+4)*8-4, -24, 17); + } + x+=4; + } +} + +#ifdef USEFPM +void Sbar_DrawFragsFPM (void) +{ + int i, k, l; + int top, bottom; + int x, y, f; + int xofs; + char num[12]; + scoreboard_t *s; + + Sbar_SortFragsFPM (); + +// draw the text + l = scoreboardlines <= 4 ? scoreboardlines : 4; + + x = 23; + if (clFPM.gametype == GAME_DEATHMATCH) + xofs = 0; + else + xofs = (vid.width - min_vid_width/*320*/)>>1; + y = vid.height - SBAR_HEIGHT - 23; + + for (i=0 ; iname[0]) + continue; + + // draw background + top = s->colors & 0xf0; + bottom = (s->colors & 15)<<4; + top = Sbar_ColorForMap (top); + bottom = Sbar_ColorForMap (bottom); + + Draw_Fill (xofs + x*8 + 10, y, 28, 4, top); + Draw_Fill (xofs + x*8 + 10, y+4, 28, 3, bottom); + + // draw number + f = s->frags; + sprintf (num, "%3i",f); + + Sbar_DrawCharacterFPM ( (x+1)*8 , -24, num[0]); + Sbar_DrawCharacterFPM ( (x+2)*8 , -24, num[1]); + Sbar_DrawCharacterFPM ( (x+3)*8 , -24, num[2]); + + if (k == clFPM.viewentity - 1) + { + Sbar_DrawCharacterFPM (x*8+2, -24, 16); + Sbar_DrawCharacterFPM ( (x+4)*8-4, -24, 17); + } + x+=4; + } +} +#endif //USEFPM + +//============================================================================= + + +/* +=============== +Sbar_DrawFace +=============== +*/ +void Sbar_DrawFace (void) +{ + int f, anim; + +// PGM 01/19/97 - team color drawing +// PGM 03/02/97 - fixed so color swatch only appears in CTF modes + if (rogue && + (cl.maxclients != 1) && + (teamplay.value>3) && + (teamplay.value<7)) + { + int top, bottom; + int xofs; + char num[12]; + scoreboard_t *s; + + s = &cl.scores[cl.viewentity - 1]; + // draw background + top = s->colors & 0xf0; + bottom = (s->colors & 15)<<4; + top = Sbar_ColorForMap (top); + bottom = Sbar_ColorForMap (bottom); + + if (cl.gametype == GAME_DEATHMATCH) + xofs = 113; + else + xofs = ((vid.width - min_vid_width/*320*/)>>1) + 113; + + Sbar_DrawPic (112, 0, rsb_teambord); + Draw_Fill (xofs, vid.height-SBAR_HEIGHT+3, 22, 9, top); + Draw_Fill (xofs, vid.height-SBAR_HEIGHT+12, 22, 9, bottom); + + // draw number + f = s->frags; + sprintf (num, "%3i",f); + + if (top==8) + { + if (num[0] != ' ') + Sbar_DrawCharacter(109, 3, 18 + num[0] - '0'); + if (num[1] != ' ') + Sbar_DrawCharacter(116, 3, 18 + num[1] - '0'); + if (num[2] != ' ') + Sbar_DrawCharacter(123, 3, 18 + num[2] - '0'); + } + else + { + Sbar_DrawCharacter ( 109, 3, num[0]); + Sbar_DrawCharacter ( 116, 3, num[1]); + Sbar_DrawCharacter ( 123, 3, num[2]); + } + + return; + } +// PGM 01/19/97 - team color drawing + + if ( (cl.items & (IT_INVISIBILITY | IT_INVULNERABILITY) ) + == (IT_INVISIBILITY | IT_INVULNERABILITY) ) + { + Sbar_DrawPic (112, 0, sb_face_invis_invuln); + return; + } + if (cl.items & IT_QUAD) + { + Sbar_DrawPic (112, 0, sb_face_quad ); + return; + } + if (cl.items & IT_INVISIBILITY) + { + Sbar_DrawPic (112, 0, sb_face_invis ); + return; + } + if (cl.items & IT_INVULNERABILITY) + { + Sbar_DrawPic (112, 0, sb_face_invuln); + return; + } + + if (cl.stats[STAT_HEALTH] >= 100) + f = 4; + else + f = cl.stats[STAT_HEALTH] / 20; + + if (cl.time <= cl.faceanimtime) + { + anim = 1; + sb_updates = 0; // make sure the anim gets drawn over + } + else + anim = 0; + Sbar_DrawPic (112, 0, sb_faces[f][anim]); +} + +#ifdef USEFPM +void Sbar_DrawFaceFPM (void) +{ + int f, anim; + +// PGM 01/19/97 - team color drawing +// PGM 03/02/97 - fixed so color swatch only appears in CTF modes + if (rogue && + (clFPM.maxclients != 1) && + (teamplay.value>3) && + (teamplay.value<7)) + { + int top, bottom; + int xofs; + char num[12]; + scoreboard_t *s; + + s = &clFPM.scores[clFPM.viewentity - 1]; + // draw background + top = s->colors & 0xf0; + bottom = (s->colors & 15)<<4; + top = Sbar_ColorForMap (top); + bottom = Sbar_ColorForMap (bottom); + + if (clFPM.gametype == GAME_DEATHMATCH) + xofs = 113; + else + xofs = ((vid.width - min_vid_width/*320*/)>>1) + 113; + + Sbar_DrawPicFPM (112, 0, rsb_teambord); + Draw_Fill (xofs, vid.height-SBAR_HEIGHT+3, 22, 9, top); + Draw_Fill (xofs, vid.height-SBAR_HEIGHT+12, 22, 9, bottom); + + // draw number + f = s->frags; + sprintf (num, "%3i",f); + + if (top==8) + { + if (num[0] != ' ') + Sbar_DrawCharacterFPM(109, 3, 18 + num[0] - '0'); + if (num[1] != ' ') + Sbar_DrawCharacterFPM(116, 3, 18 + num[1] - '0'); + if (num[2] != ' ') + Sbar_DrawCharacterFPM(123, 3, 18 + num[2] - '0'); + } + else + { + Sbar_DrawCharacterFPM ( 109, 3, num[0]); + Sbar_DrawCharacterFPM ( 116, 3, num[1]); + Sbar_DrawCharacterFPM ( 123, 3, num[2]); + } + + return; + } +// PGM 01/19/97 - team color drawing + + if ( (clFPM.items & (IT_INVISIBILITY | IT_INVULNERABILITY) ) + == (IT_INVISIBILITY | IT_INVULNERABILITY) ) + { + Sbar_DrawPicFPM (112, 0, sb_face_invis_invuln); + return; + } + if (clFPM.items & IT_QUAD) + { + Sbar_DrawPicFPM (112, 0, sb_face_quad ); + return; + } + if (clFPM.items & IT_INVISIBILITY) + { + Sbar_DrawPicFPM (112, 0, sb_face_invis ); + return; + } + if (clFPM.items & IT_INVULNERABILITY) + { + Sbar_DrawPicFPM (112, 0, sb_face_invuln); + return; + } + + if (clFPM.stats[STAT_HEALTH] >= 100) + f = 4; + else + f = clFPM.stats[STAT_HEALTH] / 20; + + if (clFPM.time <= clFPM.faceanimtime) + { + anim = 1; + sb_updates = 0; // make sure the anim gets drawn over + } + else + anim = 0; + Sbar_DrawPicFPM (112, 0, sb_faces[f][anim]); +} +#endif //USEFPM + +/* +=============== +Sbar_Draw +=============== +*/ +void Sbar_Draw (void) +{ + if (scr_con_current == vid.height) + return; // console is full screen + + if (sb_updates >= vid.numpages) + return; + + scr_copyeverything = 1; + + sb_updates++; + + if (sb_lines && vid.width > (unsigned int)min_vid_width/*320*/) + Draw_TileClear (0, vid.height - sb_lines, vid.width, sb_lines); + + if (sb_lines > 24) + { + Sbar_DrawInventory (); + if (cl.maxclients != 1) + Sbar_DrawFrags (); + } + + if (sb_showscores || cl.stats[STAT_HEALTH] <= 0) + { + Sbar_DrawPic (0, 0, sb_scorebar); + Sbar_DrawScoreboard (); + sb_updates = 0; + } + else if (sb_lines) + { + Sbar_DrawPic (0, 0, sb_sbar); + + // keys (hipnotic only) + //MED 01/04/97 moved keys here so they would not be overwritten + if (r2_mod == 1) + { + if (cl.items & IT_KEY1) + Sbar_DrawPic (209, 3, sb_items[0]); + if (cl.items & IT_KEY2) + Sbar_DrawPic (209, 12, sb_items[1]); + } + // armor + if (cl.items & IT_INVULNERABILITY) + { + Sbar_DrawNum (24, 0, 666, 3, 1); + Sbar_DrawPic (0, 0, draw_disc); + } + else + { + if (r2_mod == 2) + { + Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3, + cl.stats[STAT_ARMOR] <= 25); + if (cl.items & RIT_ARMOR3) + Sbar_DrawPic (0, 0, sb_armor[2]); + else if (cl.items & RIT_ARMOR2) + Sbar_DrawPic (0, 0, sb_armor[1]); + else if (cl.items & RIT_ARMOR1) + Sbar_DrawPic (0, 0, sb_armor[0]); + } + else + { + Sbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3 + , cl.stats[STAT_ARMOR] <= 25); + if (cl.items & IT_ARMOR3) + Sbar_DrawPic (0, 0, sb_armor[2]); + else if (cl.items & IT_ARMOR2) + Sbar_DrawPic (0, 0, sb_armor[1]); + else if (cl.items & IT_ARMOR1) + Sbar_DrawPic (0, 0, sb_armor[0]); + } + } + + // face + Sbar_DrawFace (); + + // health + Sbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3 + , cl.stats[STAT_HEALTH] <= 25); + + // ammo icon + if (r2_mod == 2) + { + if (cl.items & RIT_SHELLS) + Sbar_DrawPic (224, 0, sb_ammo[0]); + else if (cl.items & RIT_NAILS) + Sbar_DrawPic (224, 0, sb_ammo[1]); + else if (cl.items & RIT_ROCKETS) + Sbar_DrawPic (224, 0, sb_ammo[2]); + else if (cl.items & RIT_CELLS) + Sbar_DrawPic (224, 0, sb_ammo[3]); + else if (cl.items & RIT_LAVA_NAILS) + Sbar_DrawPic (224, 0, rsb_ammo[0]); + else if (cl.items & RIT_PLASMA_AMMO) + Sbar_DrawPic (224, 0, rsb_ammo[1]); + else if (cl.items & RIT_MULTI_ROCKETS) + Sbar_DrawPic (224, 0, rsb_ammo[2]); + } + else + { + if (cl.items & IT_SHELLS) + Sbar_DrawPic (224, 0, sb_ammo[0]); + else if (cl.items & IT_NAILS) + Sbar_DrawPic (224, 0, sb_ammo[1]); + else if (cl.items & IT_ROCKETS) + Sbar_DrawPic (224, 0, sb_ammo[2]); + else if (cl.items & IT_CELLS) + Sbar_DrawPic (224, 0, sb_ammo[3]); + } + + Sbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3, + cl.stats[STAT_AMMO] <= 10); + } + + if (vid.width > (unsigned int)min_vid_width/*320*/) { + if (cl.gametype == GAME_DEATHMATCH) + Sbar_MiniDeathmatchOverlay (); + } +} + +#ifdef USEFPM +void Sbar_DrawFPM (void) +{ + if (scr_con_current == vid.height) + return; // console is full screen + + if (sb_updates >= vid.numpages) + return; + + scr_copyeverything = 1; + + sb_updates++; + + if (sb_lines && vid.width > min_vid_width/*320*/) + Draw_TileClear (0, vid.height - sb_lines, vid.width, sb_lines); + + if (sb_lines > 24) + { + Sbar_DrawInventoryFPM (); + if (clFPM.maxclients != 1) + Sbar_DrawFragsFPM (); + } + + if (sb_showscores || clFPM.stats[STAT_HEALTH] <= 0) + { + Sbar_DrawPicFPM (0, 0, sb_scorebar); + Sbar_DrawScoreboardFPM (); + sb_updates = 0; + } + else if (sb_lines) + { + Sbar_DrawPicFPM (0, 0, sb_sbar); + + // keys (hipnotic only) + //MED 01/04/97 moved keys here so they would not be overwritten + if (r2_mod == 1) + { + if (clFPM.items & IT_KEY1) + Sbar_DrawPicFPM (209, 3, sb_items[0]); + if (clFPM.items & IT_KEY2) + Sbar_DrawPicFPM (209, 12, sb_items[1]); + } + // armor + if (clFPM.items & IT_INVULNERABILITY) + { + Sbar_DrawNumFPM (24, 0, 666, 3, 1); + Sbar_DrawPicFPM (0, 0, draw_disc); + } + else + { + if (r2_mod == 2) + { + Sbar_DrawNumFPM (24, 0, clFPM.stats[STAT_ARMOR], 3, + clFPM.stats[STAT_ARMOR] <= 25); + if (clFPM.items & RIT_ARMOR3) + Sbar_DrawPicFPM (0, 0, sb_armor[2]); + else if (clFPM.items & RIT_ARMOR2) + Sbar_DrawPicFPM (0, 0, sb_armor[1]); + else if (clFPM.items & RIT_ARMOR1) + Sbar_DrawPicFPM (0, 0, sb_armor[0]); + } + else + { + Sbar_DrawNumFPM (24, 0, clFPM.stats[STAT_ARMOR], 3 + , clFPM.stats[STAT_ARMOR] <= 25); + if (clFPM.items & IT_ARMOR3) + Sbar_DrawPicFPM (0, 0, sb_armor[2]); + else if (clFPM.items & IT_ARMOR2) + Sbar_DrawPicFPM (0, 0, sb_armor[1]); + else if (clFPM.items & IT_ARMOR1) + Sbar_DrawPicFPM (0, 0, sb_armor[0]); + } + } + + // face + Sbar_DrawFaceFPM (); + + // health + Sbar_DrawNumFPM (136, 0, clFPM.stats[STAT_HEALTH], 3 + , clFPM.stats[STAT_HEALTH] <= 25); + + // ammo icon + if (r2_mod == 2) + { + if (clFPM.items & RIT_SHELLS) + Sbar_DrawPicFPM (224, 0, sb_ammo[0]); + else if (clFPM.items & RIT_NAILS) + Sbar_DrawPicFPM (224, 0, sb_ammo[1]); + else if (clFPM.items & RIT_ROCKETS) + Sbar_DrawPicFPM (224, 0, sb_ammo[2]); + else if (clFPM.items & RIT_CELLS) + Sbar_DrawPicFPM (224, 0, sb_ammo[3]); + else if (clFPM.items & RIT_LAVA_NAILS) + Sbar_DrawPicFPM (224, 0, rsb_ammo[0]); + else if (clFPM.items & RIT_PLASMA_AMMO) + Sbar_DrawPicFPM (224, 0, rsb_ammo[1]); + else if (clFPM.items & RIT_MULTI_ROCKETS) + Sbar_DrawPicFPM (224, 0, rsb_ammo[2]); + } + else + { + if (clFPM.items & IT_SHELLS) + Sbar_DrawPicFPM (224, 0, sb_ammo[0]); + else if (clFPM.items & IT_NAILS) + Sbar_DrawPicFPM (224, 0, sb_ammo[1]); + else if (clFPM.items & IT_ROCKETS) + Sbar_DrawPicFPM (224, 0, sb_ammo[2]); + else if (clFPM.items & IT_CELLS) + Sbar_DrawPicFPM (224, 0, sb_ammo[3]); + } + + Sbar_DrawNumFPM (248, 0, clFPM.stats[STAT_AMMO], 3, + clFPM.stats[STAT_AMMO] <= 10); + } + + if (vid.width > min_vid_width/*320*/) { + if (clFPM.gametype == GAME_DEATHMATCH) + Sbar_MiniDeathmatchOverlayFPM (); + } +} +#endif //USEFPM + +//============================================================================= + +/* +================== +Sbar_IntermissionNumber + +================== +*/ +void Sbar_IntermissionNumber (int x, int y, int num, int digits, int color) +{ + char str[12]; + char *ptr; + int l, frame; + + l = Sbar_itoa (num, str); + ptr = str; + if (l > digits) + ptr += (l-digits); + if (l < digits) + x += (digits-l)*24; + + while (*ptr) + { + if (*ptr == '-') + frame = STAT_MINUS; + else + frame = *ptr -'0'; + + Draw_TransPic (x,y,sb_nums[color][frame]); + x += 24; + ptr++; + } +} + +#ifdef USEFPM +void Sbar_IntermissionNumberFPM (int x, int y, int num, int digits, int color) +{ + char str[12]; + char *ptr; + int l, frame; + + l = Sbar_itoa (num, str); + ptr = str; + if (l > digits) + ptr += (l-digits); + if (l < digits) + x += (digits-l)*24; + + while (*ptr) + { + if (*ptr == '-') + frame = STAT_MINUS; + else + frame = *ptr -'0'; + + Draw_TransPic (x,y,sb_nums[color][frame]); + x += 24; + ptr++; + } +} +#endif //USEFPM + +/* +================== +Sbar_DeathmatchOverlay + +================== +*/ +void Sbar_DeathmatchOverlay (void) +{ + qpic_t *pic; + int i, k, l; + int top, bottom; + int x, y, f; + char num[12]; + scoreboard_t *s; + + scr_copyeverything = 1; + scr_fullupdate = 0; + + pic = Draw_CachePic ("gfx/ranking.lmp"); + M_DrawPic ((min_vid_width/*320*/-pic->width)/2, 8, pic); + +// scores + Sbar_SortFrags (); + +// draw the text + l = scoreboardlines; + + x = 80 + ((vid.width - min_vid_width/*320*/)>>1); + y = 40; + for (i=0 ; iname[0]) + continue; + + // draw background + top = s->colors & 0xf0; + bottom = (s->colors & 15)<<4; + top = Sbar_ColorForMap (top); + bottom = Sbar_ColorForMap (bottom); + + Draw_Fill ( x, y, 40, 4, top); + Draw_Fill ( x, y+4, 40, 4, bottom); + + // draw number + f = s->frags; + sprintf (num, "%3i",f); + + Draw_Character ( x+8 , y, num[0]); + Draw_Character ( x+16 , y, num[1]); + Draw_Character ( x+24 , y, num[2]); + + if (k == cl.viewentity - 1) + Draw_Character ( x - 8, y, 12); + +#if 0 +{ + int total; + int n, minutes, tens, units; + + // draw time + total = cl.completed_time - s->entertime; + minutes = (int)total/60; + n = total - minutes*60; + tens = n/10; + units = n%10; + + sprintf (num, "%3i:%i%i", minutes, tens, units); + + Draw_String ( x+48 , y, num); +} +#endif + + // draw name + Draw_String (x+64, y, s->name); + + y += 10; + } +} + +#ifdef USEFPM +void Sbar_DeathmatchOverlayFPM (void) +{ + qpic_t *pic; + int i, k, l; + int top, bottom; + int x, y, f; + char num[12]; + scoreboard_t *s; + + scr_copyeverything = 1; + scr_fullupdate = 0; + + pic = Draw_CachePic ("gfx/ranking.lmp"); + M_DrawPic ((min_vid_width/*320*/-pic->width)/2, 8, pic); + +// scores + Sbar_SortFragsFPM (); + +// draw the text + l = scoreboardlines; + + x = 80 + ((vid.width - min_vid_width/*320*/)>>1); + y = 40; + for (i=0 ; iname[0]) + continue; + + // draw background + top = s->colors & 0xf0; + bottom = (s->colors & 15)<<4; + top = Sbar_ColorForMap (top); + bottom = Sbar_ColorForMap (bottom); + + Draw_Fill ( x, y, 40, 4, top); + Draw_Fill ( x, y+4, 40, 4, bottom); + + // draw number + f = s->frags; + sprintf (num, "%3i",f); + + Draw_Character ( x+8 , y, num[0]); + Draw_Character ( x+16 , y, num[1]); + Draw_Character ( x+24 , y, num[2]); + + if (k == clFPM.viewentity - 1) + Draw_Character ( x - 8, y, 12); + +#if 0 +{ + int total; + int n, minutes, tens, units; + + // draw time + total = clFPM.completed_time - s->entertime; + minutes = (int)total/60; + n = total - minutes*60; + tens = n/10; + units = n%10; + + sprintf (num, "%3i:%i%i", minutes, tens, units); + + Draw_String ( x+48 , y, num); +} +#endif + + // draw name + Draw_String (x+64, y, s->name); + + y += 10; + } +} +#endif //USEFPM + +/* +================== +Sbar_DeathmatchOverlay + +================== +*/ +void Sbar_MiniDeathmatchOverlay (void) +{ +// qpic_t *pic; + int i, k, l; + int top, bottom; + int x, y, f; + char num[12]; + scoreboard_t *s; + int numlines; + + if (vid.width < 512 || !sb_lines) + return; + + scr_copyeverything = 1; + scr_fullupdate = 0; + +// scores + Sbar_SortFrags (); + +// draw the text + l = scoreboardlines; + y = vid.height - sb_lines; + numlines = sb_lines/8; + if (numlines < 3) + return; + + //find us + for (i = 0; i < scoreboardlines; i++) + if (fragsort[i] == cl.viewentity - 1) + break; + + if (i == scoreboardlines) // we're not there + i = 0; + else // figure out start + i = i - numlines/2; + + if (i > scoreboardlines - numlines) + i = scoreboardlines - numlines; + if (i < 0) + i = 0; + + x = 324; + for (/* */; i < scoreboardlines && (unsigned int)y < vid.height - 8 ; i++) + { + k = fragsort[i]; + s = &cl.scores[k]; + if (!s->name[0]) + continue; + + // draw background + top = s->colors & 0xf0; + bottom = (s->colors & 15)<<4; + top = Sbar_ColorForMap (top); + bottom = Sbar_ColorForMap (bottom); + + Draw_Fill ( x, y+1, 40, 3, top); + Draw_Fill ( x, y+4, 40, 4, bottom); + + // draw number + f = s->frags; + sprintf (num, "%3i",f); + + Draw_Character ( x+8 , y, num[0]); + Draw_Character ( x+16 , y, num[1]); + Draw_Character ( x+24 , y, num[2]); + + if (k == cl.viewentity - 1) { + Draw_Character ( x, y, 16); + Draw_Character ( x + 32, y, 17); + } + +#if 0 +{ + int total; + int n, minutes, tens, units; + + // draw time + total = cl.completed_time - s->entertime; + minutes = (int)total/60; + n = total - minutes*60; + tens = n/10; + units = n%10; + + sprintf (num, "%3i:%i%i", minutes, tens, units); + + Draw_String ( x+48 , y, num); +} +#endif + + // draw name + Draw_String (x+48, y, s->name); + + y += 8; + } +} + +#ifdef USEFPM +void Sbar_MiniDeathmatchOverlayFPM (void) +{ +// qpic_t *pic; + int i, k, l; + int top, bottom; + int x, y, f; + char num[12]; + scoreboard_t *s; + int numlines; + + if (vid.width < 512 || !sb_lines) + return; + + scr_copyeverything = 1; + scr_fullupdate = 0; + +// scores + Sbar_SortFrags (); + +// draw the text + l = scoreboardlines; + y = vid.height - sb_lines; + numlines = sb_lines/8; + if (numlines < 3) + return; + + //find us + for (i = 0; i < scoreboardlines; i++) + if (fragsort[i] == clFPM.viewentity - 1) + break; + + if (i == scoreboardlines) // we're not there + i = 0; + else // figure out start + i = i - numlines/2; + + if (i > scoreboardlines - numlines) + i = scoreboardlines - numlines; + if (i < 0) + i = 0; + + x = 324; + for (/* */; i < scoreboardlines && (unsigned int)y < vid.height - 8 ; i++) + { + k = fragsort[i]; + s = &clFPM.scores[k]; + if (!s->name[0]) + continue; + + // draw background + top = s->colors & 0xf0; + bottom = (s->colors & 15)<<4; + top = Sbar_ColorForMap (top); + bottom = Sbar_ColorForMap (bottom); + + Draw_Fill ( x, y+1, 40, 3, top); + Draw_Fill ( x, y+4, 40, 4, bottom); + + // draw number + f = s->frags; + sprintf (num, "%3i",f); + + Draw_Character ( x+8 , y, num[0]); + Draw_Character ( x+16 , y, num[1]); + Draw_Character ( x+24 , y, num[2]); + + if (k == clFPM.viewentity - 1) { + Draw_Character ( x, y, 16); + Draw_Character ( x + 32, y, 17); + } + +#if 0 +{ + int total; + int n, minutes, tens, units; + + // draw time + total = clFPM.completed_time - s->entertime; + minutes = (int)total/60; + n = total - minutes*60; + tens = n/10; + units = n%10; + + sprintf (num, "%3i:%i%i", minutes, tens, units); + + Draw_String ( x+48 , y, num); +} +#endif + + // draw name + Draw_String (x+48, y, s->name); + + y += 8; + } +} +#endif //USEFPM +/* +================== +Sbar_IntermissionOverlay + +================== +*/ +void Sbar_IntermissionOverlay (void) +{ + qpic_t *pic; + int dig; + int num; + + scr_copyeverything = 1; + scr_fullupdate = 0; + + if (cl.gametype == GAME_DEATHMATCH) + { + Sbar_DeathmatchOverlay (); + return; + } + + pic = Draw_CachePic ("gfx/complete.lmp"); + Draw_Pic ((vid.width/2)-94, (vid.height/2) - 96, pic); + pic = Draw_CachePic ("gfx/inter.lmp"); + Draw_TransPic ((vid.width/2)-160, (vid.height/2) - 64, pic); + + dig = cl.completed_time/60; + Sbar_IntermissionNumber (vid.width/2, (vid.height/2) - 56, dig, 3, 0); + num = cl.completed_time - dig*60; + + Draw_TransPic ((vid.width/2)+74 ,(vid.height/2)- 56,sb_colon); + Draw_TransPic ((vid.width/2)+86 ,(vid.height/2)- 56,sb_nums[0][num/10]); + Draw_TransPic ((vid.width/2)+106,(vid.height/2)- 56,sb_nums[0][num%10]); + + Sbar_IntermissionNumber ((vid.width/2), (vid.height/2)- 16, cl.stats[STAT_SECRETS], 3, 0); + Draw_TransPic ((vid.width/2)+72,(vid.height/2)- 16,sb_slash); + Sbar_IntermissionNumber ((vid.width/2)+80, (vid.height/2)- 16, cl.stats[STAT_TOTALSECRETS], 3, 0); + + Sbar_IntermissionNumber ((vid.width/2), (vid.height/2)+ 24, cl.stats[STAT_MONSTERS], 3, 0); + Draw_TransPic ((vid.width/2)+72,(vid.height/2)+ 24,sb_slash); + Sbar_IntermissionNumber ((vid.width/2)+80, (vid.height/2)+ 24, cl.stats[STAT_TOTALMONSTERS], 3, 0); + +} + +#ifdef USEFPM +void Sbar_IntermissionOverlayFPM (void) +{ + qpic_t *pic; + int dig; + int num; + + scr_copyeverything = 1; + scr_fullupdate = 0; + + if (clFPM.gametype == GAME_DEATHMATCH) + { + Sbar_DeathmatchOverlayFPM (); + return; + } + + pic = Draw_CachePic ("gfx/complete.lmp"); + Draw_Pic (64, 24, pic); + + pic = Draw_CachePic ("gfx/inter.lmp"); + Draw_TransPic (0, 56, pic); + +// time + dig = clFPM.completed_time/60; + Sbar_IntermissionNumberFPM (160, 64, dig, 3, 0); + num = clFPM.completed_time - dig*60; + Draw_TransPic (234,64,sb_colon); + Draw_TransPic (246,64,sb_nums[0][num/10]); + Draw_TransPic (266,64,sb_nums[0][num%10]); + + Sbar_IntermissionNumberFPM (160, 104, clFPM.stats[STAT_SECRETS], 3, 0); + Draw_TransPic (232,104,sb_slash); + Sbar_IntermissionNumberFPM (240, 104, clFPM.stats[STAT_TOTALSECRETS], 3, 0); + + Sbar_IntermissionNumberFPM (160, 144, clFPM.stats[STAT_MONSTERS], 3, 0); + Draw_TransPic (232,144,sb_slash); + Sbar_IntermissionNumberFPM (240, 144, clFPM.stats[STAT_TOTALMONSTERS], 3, 0); + +} +#endif //USEFPM + +/* +================== +Sbar_FinaleOverlay + +================== +*/ +void Sbar_FinaleOverlay (void) +{ + qpic_t *pic; + + scr_copyeverything = 1; + + pic = Draw_CachePic ("gfx/finale.lmp"); + Draw_TransPic ( (vid.width-pic->width)/2, 16, pic); +} diff --git a/project/jni/application/quake/source/sbar.h b/project/jni/application/quake/source/sbar.h new file mode 100644 index 000000000..8afe5f03e --- /dev/null +++ b/project/jni/application/quake/source/sbar.h @@ -0,0 +1,40 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// the status bar is only redrawn if something has changed, but if anything +// does, the entire thing will be redrawn for the next vid.numpages frames. + +#define SBAR_HEIGHT 24 + +extern int sb_lines; // scan lines to draw + +void Sbar_Init (void); + +void Sbar_Changed (void); +// call whenever any of the client stats represented on the sbar changes + +void Sbar_Draw (void); +void Sbar_DrawFPM (void); +// called every frame by screen + +void Sbar_IntermissionOverlay (void); +// called each frame after the level has been completed + +void Sbar_FinaleOverlay (void); diff --git a/project/jni/application/quake/source/screen.c b/project/jni/application/quake/source/screen.c new file mode 100644 index 000000000..18f1f0488 --- /dev/null +++ b/project/jni/application/quake/source/screen.c @@ -0,0 +1,1158 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// screen.c -- master for refresh, status bar, console, chat, notify, etc + +#include "quakedef.h" +#include "r_local.h" + +double lastframetime; +int lastfps; + +// only the refresh window will be updated unless these variables are flagged +int scr_copytop; +int scr_copyeverything; + +float scr_con_current; +float scr_conlines; // lines of console to display + +float oldscreensize, oldfov; +cvar_t scr_viewsize = {"viewsize","100", true}; +cvar_t scr_fov = {"fov","90"}; // 10 - 170 +cvar_t scr_conspeed = {"scr_conspeed","300"}; +cvar_t scr_centertime = {"scr_centertime","2"}; +cvar_t scr_showram = {"showram","1"}; +cvar_t scr_showturtle = {"showturtle","0"}; +cvar_t scr_showpause = {"showpause","1"}; +cvar_t scr_printspeed = {"scr_printspeed","8"}; + +qboolean scr_initialized; // ready to draw + +qpic_t *scr_ram; +qpic_t *scr_net; +qpic_t *scr_turtle; + +int scr_fullupdate; + +int clearconsole; +int clearnotify; + +viddef_t vid; // global video state + +vrect_t *pconupdate; +vrect_t scr_vrect; + +qboolean scr_disabled_for_loading; +qboolean scr_drawloading; +float scr_disabled_time; +qboolean scr_skipupdate; + +qboolean block_drawing; + +void SCR_ScreenShot_f (void); + +/* +=============================================================================== + +CENTER PRINTING + +=============================================================================== +*/ + +char scr_centerstring[1024]; +float scr_centertime_start; // for slow victory printing +float scr_centertime_off; +int scr_center_lines; +int scr_erase_lines; +int scr_erase_center; + +/* +============== +SCR_CenterPrint + +Called for important messages that should stay in the center of the screen +for a few moments +============== +*/ +void SCR_CenterPrint (char *str) +{ + strncpy (scr_centerstring, str, sizeof(scr_centerstring)-1); + scr_centertime_off = scr_centertime.value; + scr_centertime_start = (float)cl.time; + +// count the number of lines for centering + scr_center_lines = 1; + while (*str) + { + if (*str == '\n') + scr_center_lines++; + str++; + } +} + +void SCR_EraseCenterString (void) +{ + int y; + + if (scr_erase_center++ > vid.numpages) + { + scr_erase_lines = 0; + return; + } + + if (scr_center_lines <= 4) + y = (int)(vid.height*0.35); + else + y = 48; + + scr_copytop = 1; + Draw_TileClear (0, y,vid.width, 8*scr_erase_lines); +} + +void SCR_DrawCenterString (void) +{ + char *start; + int l; + int j; + int x, y; + int remaining; + +// the finale prints the characters one at a time + if (cl.intermission) + remaining = (int)(scr_printspeed.value * (cl.time - scr_centertime_start)); + else + remaining = 9999; + + scr_erase_center = 0; + start = scr_centerstring; + + if (scr_center_lines <= 4) + y = (int)(vid.height*0.35); + else + y = 48; + + do + { + // scan the width of the line + for (l=0 ; l<40 ; l++) + if (start[l] == '\n' || !start[l]) + break; + //Dan: fixed to work with screens < 320 pixels + if (l*8>(int)vid.width) x=0; + else x = (vid.width - l*8)/2; + for (j=0 ; j scr_erase_lines) + scr_erase_lines = scr_center_lines; + + scr_centertime_off -= (float)host_frametime; + + if (scr_centertime_off <= 0 && !cl.intermission) + return; + if (key_dest != key_game) + return; + + SCR_DrawCenterString (); +} + +//============================================================================= + +/* +==================== +CalcFov +==================== +*/ +float CalcFov (float fov_x, float width, float height) +{ + float a; + float x; + + if (fov_x < 1 || fov_x > 179) + Sys_Error ("Bad fov: %f", fov_x); + + x = (float)(width/tan(fov_x/360*M_PI)); + + a = (float)atan (height/x); + + a = (float)(a*360/M_PI); + + return a; +} + + +/* +================= +SCR_CalcRefdef + +Must be called whenever vid changes +Internal use only +================= +*/ +static void SCR_CalcRefdef (void) +{ + vrect_t vrect; + float size; + + scr_fullupdate = 0; // force a background redraw + vid.recalc_refdef = 0; + +// force the status bar to redraw + Sbar_Changed (); + +//======================================== + +// bound viewsize + if (scr_viewsize.value < 30) + Cvar_Set ("viewsize","30"); + if (scr_viewsize.value > 120) + Cvar_Set ("viewsize","120"); + +// bound field of view + if (scr_fov.value < 10) + Cvar_Set ("fov","10"); + if (scr_fov.value > 170) + Cvar_Set ("fov","170"); + + // widescreen hack. put the two lines below back and remove the block underneath to return to normal fov setting + + // r_refdef.fov_x = scr_fov.value; + // r_refdef.fov_y = CalcFov (r_refdef.fov_x, (float)r_refdef.vrect.width, (float)r_refdef.vrect.height); + + //widescreen fov from quakesrc.org + + if (scr_fov.value > 89 && scr_fov.value < 91) + { + // default fov + float screenaspect = (float) vid.width / (float) vid.height; + + if (screenaspect > 1.34) + { + // widescreen - width is based on a target height + // correct y fov for the full height view + // r_refdef.fov_y = 73.739797; + // r_refdef.fov_x = CalcFov (73.739797, r_refdef.vrect.height, r_refdef.vrect.width); + r_refdef.fov_y = 65; + r_refdef.fov_x = CalcFov (65, r_refdef.vrect.height, r_refdef.vrect.width); + } + else + { + // tallscreen or default fov where height is based on a target width + // correct x fov for the full width view + r_refdef.fov_x = 90; + r_refdef.fov_y = CalcFov (90, r_refdef.vrect.width, r_refdef.vrect.height); + } + } + else + { + // manual fov + r_refdef.fov_x = scr_fov.value; + r_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height); + } + + +// intermission is always full screen + if (cl.intermission) + size = 120; + else + size = scr_viewsize.value; + + if (size >= 120) + sb_lines = 0; // no status bar at all + else if (size >= 110) + sb_lines = 24; // no inventory + else + sb_lines = 24+16+8; + + +// these calculations mirror those in R_Init() for r_refdef, but take no +// account of water warping + vrect.x = 0; + vrect.y = 0; + vrect.width = vid.width; + vrect.height = vid.height; + + R_SetVrect (&vrect, &scr_vrect, sb_lines); + +// guard against going from one mode to another that's less than half the +// vertical resolution + if (scr_con_current > vid.height) + scr_con_current = (float)vid.height; + +// notify the refresh of the change + R_ViewChanged (&vrect, sb_lines, vid.aspect); +} + +#ifdef USEFPM +static void SCR_CalcRefdefFPM (void) +{ + vrect_t vrect; + fixedpoint_t size; + + scr_fullupdate = 0; // force a background redraw + vid.recalc_refdef = 0; + +// force the status bar to redraw + Sbar_Changed (); + +//======================================== + +// bound viewsize + if (scr_viewsize.value < 30) + Cvar_Set ("viewsize","30"); + if (scr_viewsize.value > 120) + Cvar_Set ("viewsize","120"); + +// bound field of view + if (scr_fov.value < 10) + Cvar_Set ("fov","10"); + if (scr_fov.value > 170) + Cvar_Set ("fov","170"); + + r_refdefFPM.fov_x = FPM_FROMFLOAT(scr_fov.value); + r_refdefFPM.fov_y = FPM_FROMFLOAT(CalcFov (scr_fov.value, (float)r_refdefFPM.vrect.width, (float)r_refdefFPM.vrect.height)); + +// intermission is always full screen + if (cl.intermission) + size = 120; + else + size = (long)scr_viewsize.value; + + if (size >= 120) + sb_lines = 0; // no status bar at all + else if (size >= 110) + sb_lines = 24; // no inventory + else + sb_lines = 24+16+8; + +// these calculations mirror those in R_Init() for r_refdef, but take no +// account of water warping + vrect.x = 0; + vrect.y = 0; + vrect.width = vid.width; + vrect.height = vid.height; + + R_SetVrectFPM (&vrect, &scr_vrect, sb_lines); + +// guard against going from one mode to another that's less than half the +// vertical resolution + if (scr_con_current > vid.height) + scr_con_current = (float)vid.height; + +// notify the refresh of the change + //R_ViewChangedFPM (&vrect, sb_lines, FPM_FROMFLOAT(vid.aspect)); // FPM doesn't exist + R_ViewChanged (&vrect, sb_lines, FPM_FROMFLOAT(vid.aspect)); +} +#endif //USEFPM + +/* +================= +SCR_SizeUp_f + +Keybinding command +================= +*/ +void SCR_SizeUp_f (void) +{ + Cvar_SetValue ("viewsize",scr_viewsize.value+10); + vid.recalc_refdef = 1; +} + + +/* +================= +SCR_SizeDown_f + +Keybinding command +================= +*/ +void SCR_SizeDown_f (void) +{ + Cvar_SetValue ("viewsize",scr_viewsize.value-10); + vid.recalc_refdef = 1; +} + +//============================================================================ + +/* +================== +SCR_Init +================== +*/ +void SCR_Init (void) +{ + Cvar_RegisterVariable (&scr_fov); + Cvar_RegisterVariable (&scr_viewsize); + Cvar_RegisterVariable (&scr_conspeed); + Cvar_RegisterVariable (&scr_showram); + Cvar_RegisterVariable (&scr_showturtle); + Cvar_RegisterVariable (&scr_showpause); + Cvar_RegisterVariable (&scr_centertime); + Cvar_RegisterVariable (&scr_printspeed); + +// +// register our commands +// + Cmd_AddCommand ("screenshot",SCR_ScreenShot_f); + Cmd_AddCommand ("sizeup",SCR_SizeUp_f); + Cmd_AddCommand ("sizedown",SCR_SizeDown_f); + + scr_ram = Draw_PicFromWad ("ram"); + scr_net = Draw_PicFromWad ("net"); + scr_turtle = Draw_PicFromWad ("turtle"); + + scr_initialized = true; +} + + + +/* +============== +SCR_DrawRam +============== +*/ +void SCR_DrawRam (void) +{ + if (!scr_showram.value) + return; + + if (!r_cache_thrash) + return; + + Draw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram); +} + +/* +============== +SCR_DrawTurtle +============== +*/ +void SCR_DrawTurtle (void) +{ + static int count; + + if (!scr_showturtle.value) + return; + + if (host_frametime < 0.1) + { + count = 0; + return; + } + + count++; + if (count < 3) + return; + + Draw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle); +} + +/* +============== +SCR_DrawNet +============== +*/ +void SCR_DrawNet (void) +{ + if (realtime - cl.last_received_message < 0.3) + return; + if (cls.demoplayback) + return; + + Draw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net); +} + +// 2001-11-31 FPS display by QuakeForge/Muff start +/* +============== +SCR_DrawFPS +============== +*/ +//muff - hacked out of SourceForge implementation + modified + +void SCR_DrawFPS (void) { + extern cvar_t cl_showfps; + static double lastframetime; + double t; + extern int fps_count; + static int lastfps; + int x, y; + char st[80]; + + if (!cl_showfps.value) + return; + + t = Sys_FloatTime (); + + if ((t - lastframetime) >= 1.0) { + lastfps = fps_count; + fps_count = 0; + lastframetime = t; + } + + sprintf(st, "%3d FPS", lastfps); + + x = 0 ; + y = 0 ; + + Draw_String(x, y, st); +} + +// 2001-11-31 FPS display by QuakeForge/Muff end + + + +/* +============== +DrawPause +============== +*/ +void SCR_DrawPause (void) +{ + qpic_t *pic; + + if (!scr_showpause.value) // turn off for screenshots + return; + + if (!cl.paused) + return; + + pic = Draw_CachePic ("gfx/pause.lmp"); + Draw_Pic ( (vid.width - pic->width)/2, + (vid.height - 48 - pic->height)/2, pic); +} + + + +/* +============== +SCR_DrawLoading +============== +*/ +void SCR_DrawLoading (void) +{ + qpic_t *pic; + + if (!scr_drawloading) + return; + + pic = Draw_CachePic ("gfx/loading.lmp"); + Draw_Pic ( (vid.width - pic->width)/2, + (vid.height - 48 - pic->height)/2, pic); +} + + + +//============================================================================= + + +/* +================== +SCR_SetUpToDrawConsole +================== +*/ +void SCR_SetUpToDrawConsole (void) +{ + Con_CheckResize (); + + if (scr_drawloading) + return; // never a console with loading plaque + +// decide on the height of the console +#ifdef USEFPM + con_forcedup = !clFPM.worldmodel || cls.signon != SIGNONS; +#else + con_forcedup = !cl.worldmodel || cls.signon != SIGNONS; +#endif + + if (con_forcedup) + { + scr_conlines = (float)vid.height; // full screen + scr_con_current = scr_conlines; + } + else if (key_dest == key_console) + scr_conlines = (float)(vid.height/2); // half screen + else + scr_conlines = 0; // none visible + + if (scr_conlines < scr_con_current) + { + scr_con_current -= (float)(scr_conspeed.value*host_frametime); + if (scr_conlines > scr_con_current) + scr_con_current = scr_conlines; + + } + else if (scr_conlines > scr_con_current) + { + scr_con_current += (float)(scr_conspeed.value*host_frametime); + if (scr_conlines < scr_con_current) + scr_con_current = scr_conlines; + } + + if (clearconsole++ < vid.numpages) + { + scr_copytop = 1; + Draw_TileClear (0,(int)scr_con_current,vid.width, vid.height - (int)scr_con_current); + Sbar_Changed (); + } + else if (clearnotify++ < vid.numpages) + { + scr_copytop = 1; + Draw_TileClear (0,0,vid.width, con_notifylines); + } + else + con_notifylines = 0; +} + +/* +================== +SCR_DrawConsole +================== +*/ +void SCR_DrawConsole (void) +{ + if (scr_con_current) + { + scr_copyeverything = 1; + Con_DrawConsole ((int)scr_con_current, true); + clearconsole = 0; + } + else + { + if (key_dest == key_game || key_dest == key_message) + Con_DrawNotify (); // only draw notify in game + } +} + + +/* +============================================================================== + + SCREEN SHOTS + +============================================================================== +*/ + + +typedef struct +{ + char manufacturer; + char version; + char encoding; + char bits_per_pixel; + unsigned short xmin,ymin,xmax,ymax; + unsigned short hres,vres; + unsigned char palette[48]; + char reserved; + char color_planes; + unsigned short bytes_per_line; + unsigned short palette_type; + char filler[58]; + unsigned char data; // unbounded +} pcx_t; + +/* +============== +WritePCXfile +============== +*/ +void WritePCXfile (char *filename, byte *data, int width, int height, + int rowbytes, byte *palette) +{ + int i, j, length; + pcx_t *pcx; + byte *pack; + + pcx = Hunk_TempAlloc (width*height*2+1000); + if (pcx == NULL) + { + Con_Printf("SCR_ScreenShot_f: not enough memory\n"); + return; + } + + pcx->manufacturer = 0x0a; // PCX id + pcx->version = 5; // 256 color + pcx->encoding = 1; // uncompressed + pcx->bits_per_pixel = 8; // 256 color + pcx->xmin = 0; + pcx->ymin = 0; + pcx->xmax = LittleShort((short)(width-1)); + pcx->ymax = LittleShort((short)(height-1)); + pcx->hres = LittleShort((short)width); + pcx->vres = LittleShort((short)height); + Q_memset (pcx->palette,0,sizeof(pcx->palette)); + pcx->color_planes = 1; // chunky image + pcx->bytes_per_line = LittleShort((short)width); + pcx->palette_type = LittleShort(2); // not a grey scale + Q_memset (pcx->filler,0,sizeof(pcx->filler)); + +// pack the image + pack = &pcx->data; + + for (i=0 ; i 60) + { + scr_disabled_for_loading = false; + Con_Printf ("load failed.\n"); + } + else + return; + } + + if (cls.state == ca_dedicated) + return; // stdout only + + if (!scr_initialized || !con_initialized) + return; // not initialized yet + + if (scr_viewsize.value != oldscr_viewsize) + { + oldscr_viewsize = scr_viewsize.value; + vid.recalc_refdef = 1; + } + +// +// check for vid changes +// + if (oldfov != scr_fov.value) + { + oldfov = scr_fov.value; + vid.recalc_refdef = true; + } + + if (oldlcd_x != lcd_x.value) + { + oldlcd_x = lcd_x.value; + vid.recalc_refdef = true; + } + + if (oldscreensize != scr_viewsize.value) + { + oldscreensize = scr_viewsize.value; + vid.recalc_refdef = true; + } + + if (vid.recalc_refdef) + { + // something changed, so reorder the screen +#ifdef USEFPM + SCR_CalcRefdefFPM (); +#else + SCR_CalcRefdef (); +#endif + } + +// +// do 3D refresh drawing, and then update the screen +// +// D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly + + if (scr_fullupdate++ < vid.numpages) + { // clear the entire screen + scr_copyeverything = 1; + Draw_TileClear (0,0,vid.width,vid.height); + Sbar_Changed (); + } + + pconupdate = NULL; + + + SCR_SetUpToDrawConsole (); + SCR_EraseCenterString (); + +// D_DisableBackBufferAccess (); // for adapters that can't stay mapped in + // for linear writes all the time + +// VID_LockBuffer (); + +#ifdef USEFPM + V_RenderViewFPM(); +#else + V_RenderView (); +#endif + +// VID_UnlockBuffer (); + +// D_EnableBackBufferAccess (); // of all overlay stuff if drawing directly + + if (scr_drawdialog) + { +// GpError("scr_drawdialog",3); + Sbar_Draw (); + Draw_FadeScreen (); + SCR_DrawNotifyString (); + scr_copyeverything = true; + } + else if (scr_drawloading) + { + GpError("scr_drawloading",3); + SCR_DrawLoading (); + Sbar_Draw (); + } + else if (cl.intermission == 1 && key_dest == key_game) + { + GpError("cl_intermission==1",3); + Sbar_IntermissionOverlay (); + } + else if (cl.intermission == 2 && key_dest == key_game) + { + GpError("cl_intermission==2",3); + Sbar_FinaleOverlay (); + SCR_CheckDrawCenterString (); + } + else if (cl.intermission == 3 && key_dest == key_game) + { + GpError("cl_intermission==3",3); + SCR_CheckDrawCenterString (); + } + else + { + SCR_DrawRam (); + SCR_DrawNet (); + SCR_DrawTurtle (); + SCR_DrawFPS (); // 2001-11-31 FPS display by QuakeForge/Muff + SCR_DrawPause (); + + SCR_CheckDrawCenterString (); +#ifdef USEFPM + Sbar_DrawFPM (); +#else + Sbar_Draw (); +#endif + SCR_DrawConsole (); + M_Draw (); + } + +// D_DisableBackBufferAccess (); // for adapters that can't stay mapped in + // for linear writes all the time + if (pconupdate) + { + D_UpdateRects (pconupdate); + } + + V_UpdatePalette (); + +// +// update one of three areas +// + + if (scr_copyeverything) + { + vrect.x = 0; + vrect.y = 0; + vrect.width = vid.width; + vrect.height = vid.height; + vrect.pnext = 0; + + VID_Update (&vrect); + } + else if (scr_copytop) + { + vrect.x = 0; + vrect.y = 0; + vrect.width = vid.width; + vrect.height = vid.height - sb_lines; + vrect.pnext = 0; + + VID_Update (&vrect); + } + else + { + vrect.x = scr_vrect.x; + vrect.y = scr_vrect.y; + vrect.width = scr_vrect.width; + vrect.height = scr_vrect.height; + vrect.pnext = 0; + + VID_Update (&vrect); + } +} + + +/* +================== +SCR_UpdateWholeScreen +================== +*/ +void SCR_UpdateWholeScreen (void) +{ + scr_fullupdate = 0; + SCR_UpdateScreen (); +} diff --git a/project/jni/application/quake/source/screen.h b/project/jni/application/quake/source/screen.h new file mode 100644 index 000000000..154f3e000 --- /dev/null +++ b/project/jni/application/quake/source/screen.h @@ -0,0 +1,57 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// screen.h + +void SCR_Init (void); + +void SCR_UpdateScreen (void); + + +void SCR_SizeUp (void); +void SCR_SizeDown (void); +void SCR_BringDownConsole (void); +void SCR_CenterPrint (char *str); + +void SCR_BeginLoadingPlaque (void); +void SCR_EndLoadingPlaque (void); + +int SCR_ModalMessage (char *text); + +extern float scr_con_current; +extern float scr_conlines; // lines of console to display + +extern int scr_fullupdate; // set to 0 to force full redraw +extern int sb_lines; + +extern int clearnotify; // set to 0 whenever notify text is drawn +extern qboolean scr_disabled_for_loading; +extern qboolean scr_skipupdate; + +extern cvar_t scr_viewsize; + +extern cvar_t scr_viewsize; + +// only the refresh window will be updated unless these variables are flagged +extern int scr_copytop; +extern int scr_copyeverything; + +extern qboolean block_drawing; + +void SCR_UpdateWholeScreen (void); diff --git a/project/jni/application/quake/source/server.h b/project/jni/application/quake/source/server.h new file mode 100644 index 000000000..561aab51b --- /dev/null +++ b/project/jni/application/quake/source/server.h @@ -0,0 +1,356 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// server.h + +typedef struct +{ + int maxclients; + int maxclientslimit; + struct client_s *clients; // [maxclients] + int serverflags; // episode completion information + qboolean changelevel_issued; // cleared when at SV_SpawnServer +} server_static_t; + +typedef struct +{ + int maxclients; + int maxclientslimit; + struct client_FPM_s *clients; // [maxclients] + int serverflags; // episode completion information + qboolean changelevel_issued; // cleared when at SV_SpawnServer +} server_static_FPM_t; + +//============================================================================= + +typedef enum {ss_loading, ss_active} server_state_t; + +typedef struct +{ + qboolean active; // false if only a net client + + qboolean paused; + qboolean loadgame; // handle connections specially + + double time; + + int lastcheck; // used by PF_checkclient + double lastchecktime; + + char name[64]; // map name +#ifdef QUAKE2 + char startspot[64]; +#endif + char modelname[64]; // maps/.bsp, for model_precache[0] + struct model_s *worldmodel; + char *model_precache[MAX_MODELS]; // NULL terminated + struct model_s *models[MAX_MODELS]; + char *sound_precache[MAX_SOUNDS]; // NULL terminated + char *lightstyles[MAX_LIGHTSTYLES]; + int num_edicts; + int max_edicts; + edict_t *edicts; // can NOT be array indexed, because + // edict_t is variable sized, but can + // be used to reference the world ent + server_state_t state; // some actions are only valid during load + + sizebuf_t datagram; + byte datagram_buf[MAX_DATAGRAM]; + + sizebuf_t reliable_datagram; // copied to all clients at end of frame + byte reliable_datagram_buf[MAX_DATAGRAM]; + + sizebuf_t signon; + byte signon_buf[8192]; +} server_t; + +typedef struct +{ + qboolean active; // false if only a net client + + qboolean paused; + qboolean loadgame; // handle connections specially + + double time; + + int lastcheck; // used by PF_checkclient + double lastchecktime; + + char name[64]; // map name +#ifdef QUAKE2 + char startspot[64]; +#endif + char modelname[64]; // maps/.bsp, for model_precache[0] + struct model_FPM_s *worldmodel; + char *model_precache[MAX_MODELS]; // NULL terminated + struct model_FPM_s *models[MAX_MODELS]; + char *sound_precache[MAX_SOUNDS]; // NULL terminated + char *lightstyles[MAX_LIGHTSTYLES]; + int num_edicts; + int max_edicts; + edict_FPM_t *edicts; // can NOT be array indexed, because + // edict_t is variable sized, but can + // be used to reference the world ent + server_state_t state; // some actions are only valid during load + + sizebuf_t datagram; + byte datagram_buf[MAX_DATAGRAM]; + + sizebuf_t reliable_datagram; // copied to all clients at end of frame + byte reliable_datagram_buf[MAX_DATAGRAM]; + + sizebuf_t signon; + byte signon_buf[8192]; +} server_FPM_t; + + +#define NUM_PING_TIMES 16 +#define NUM_SPAWN_PARMS 16 + +typedef struct client_s +{ + qboolean active; // false = client is free + qboolean spawned; // false = don't send datagrams + qboolean dropasap; // has been told to go to another level + qboolean privileged; // can execute any host command + qboolean sendsignon; // only valid before spawned + + double last_message; // reliable messages must be sent + // periodically + + struct qsocket_s *netconnection; // communications handle + + usercmd_t cmd; // movement + vec3_t wishdir; // intended motion calced from cmd + + sizebuf_t message; // can be added to at any time, + // copied and clear once per frame + byte msgbuf[MAX_MSGLEN]; + edict_t *edict; // EDICT_NUM(clientnum+1) + char name[32]; // for printing to other people + int colors; + + float ping_times[NUM_PING_TIMES]; + int num_pings; // ping_times[num_pings%NUM_PING_TIMES] + +// spawn parms are carried from level to level + float spawn_parms[NUM_SPAWN_PARMS]; + +// client known data for deltas + int old_frags; +} client_t; + +typedef struct client_FPM_s +{ + qboolean active; // false = client is free + qboolean spawned; // false = don't send datagrams + qboolean dropasap; // has been told to go to another level + qboolean privileged; // can execute any host command + qboolean sendsignon; // only valid before spawned + + double last_message; // reliable messages must be sent + // periodically + + struct qsocket_s *netconnection; // communications handle + + usercmd_t cmd; // movement + vec3_FPM_t wishdir; // intended motion calced from cmd + + sizebuf_t message; // can be added to at any time, + // copied and clear once per frame + byte msgbuf[MAX_MSGLEN]; + edict_FPM_t *edict; // EDICT_NUM(clientnum+1) + char name[32]; // for printing to other people + int colors; + + float ping_times[NUM_PING_TIMES]; + int num_pings; // ping_times[num_pings%NUM_PING_TIMES] + +// spawn parms are carried from level to level + float spawn_parms[NUM_SPAWN_PARMS]; + +// client known data for deltas + int old_frags; +} client_FPM_t; + +//============================================================================= + +// edict->movetype values +#define MOVETYPE_NONE 0 // never moves +#define MOVETYPE_ANGLENOCLIP 1 +#define MOVETYPE_ANGLECLIP 2 +#define MOVETYPE_WALK 3 // gravity +#define MOVETYPE_STEP 4 // gravity, special edge handling +#define MOVETYPE_FLY 5 +#define MOVETYPE_TOSS 6 // gravity +#define MOVETYPE_PUSH 7 // no clip to world, push and crush +#define MOVETYPE_NOCLIP 8 +#define MOVETYPE_FLYMISSILE 9 // extra size to monsters +#define MOVETYPE_BOUNCE 10 +#ifdef QUAKE2 +#define MOVETYPE_BOUNCEMISSILE 11 // bounce w/o gravity +#define MOVETYPE_FOLLOW 12 // track movement of aiment +#endif + +// edict->solid values +#define SOLID_NOT 0 // no interaction with other objects +#define SOLID_TRIGGER 1 // touch on edge, but not blocking +#define SOLID_BBOX 2 // touch on edge, block +#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground +#define SOLID_BSP 4 // bsp clip, touch on edge, block + +// edict->deadflag values +#define DEAD_NO 0 +#define DEAD_DYING 1 +#define DEAD_DEAD 2 + +#define DAMAGE_NO 0 +#define DAMAGE_YES 1 +#define DAMAGE_AIM 2 + +// edict->flags +#define FL_FLY 1 +#define FL_SWIM 2 +//#define FL_GLIMPSE 4 +#define FL_CONVEYOR 4 +#define FL_CLIENT 8 +#define FL_INWATER 16 +#define FL_MONSTER 32 +#define FL_GODMODE 64 +#define FL_NOTARGET 128 +#define FL_ITEM 256 +#define FL_ONGROUND 512 +#define FL_PARTIALGROUND 1024 // not all corners are valid +#define FL_WATERJUMP 2048 // player jumping out of water +#define FL_JUMPRELEASED 4096 // for jump debouncing +#ifdef QUAKE2 +#define FL_FLASHLIGHT 8192 +#define FL_ARCHIVE_OVERRIDE 1048576 +#endif + +// entity effects + +#define EF_BRIGHTFIELD 1 +#define EF_MUZZLEFLASH 2 +#define EF_BRIGHTLIGHT 4 +#define EF_DIMLIGHT 8 +#ifdef QUAKE2 +#define EF_DARKLIGHT 16 +#define EF_DARKFIELD 32 +#define EF_LIGHT 64 +#define EF_NODRAW 128 +#endif + +#define SPAWNFLAG_NOT_EASY 256 +#define SPAWNFLAG_NOT_MEDIUM 512 +#define SPAWNFLAG_NOT_HARD 1024 +#define SPAWNFLAG_NOT_DEATHMATCH 2048 + +#ifdef QUAKE2 +// server flags +#define SFL_EPISODE_1 1 +#define SFL_EPISODE_2 2 +#define SFL_EPISODE_3 4 +#define SFL_EPISODE_4 8 +#define SFL_NEW_UNIT 16 +#define SFL_NEW_EPISODE 32 +#define SFL_CROSS_TRIGGERS 65280 +#endif + +//============================================================================ + +extern cvar_t teamplay; +extern cvar_t skill; +extern cvar_t deathmatch; +extern cvar_t coop; +extern cvar_t fraglimit; +extern cvar_t timelimit; + +extern server_static_t svs; // persistant server info +extern server_static_FPM_t svsFPM; // persistant server info +extern server_t sv; // local server +extern server_FPM_t svFPM; // local server + +extern client_t *host_client; +extern client_FPM_t *host_clientFPM; + +extern jmp_buf host_abortserver; + +extern double host_time; + +extern edict_t *sv_player; +extern edict_FPM_t *sv_playerFPM; + +//=========================================================== + +void SV_Init (void); + +void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count); +void SV_StartParticleFPM (vec3_FPM_t org, vec3_FPM_t dir, int color, int count); +void SV_StartSound (edict_t *entity, int channel, char *sample, int volume, + float attenuation); +void SV_StartSoundFPM (edict_FPM_t *entity, int channel, char *sample, int volume, + float attenuation); + +void SV_DropClient (qboolean crash); +void SV_DropClientFPM (qboolean crash); + +void SV_SendClientMessages (void); +void SV_ClearDatagram (void); + +int SV_ModelIndex (char *name); +int SV_ModelIndexFPM (char *name); + +void SV_SetIdealPitch (void); +void SV_SetIdealPitchFPM (void); + +void SV_AddUpdates (void); + +void SV_ClientThink (void); +void SV_AddClientToServer (struct qsocket_s *ret); + +void SV_ClientPrintf (char *fmt, ...); +void SV_BroadcastPrintf (char *fmt, ...); + +void SV_Physics (void); +void SV_PhysicsFPM (void); + +qboolean SV_CheckBottom (edict_t *ent); +qboolean SV_CheckBottomFPM (edict_FPM_t *ent); +qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink); +qboolean SV_movestepFPM (edict_FPM_t *ent, vec3_FPM_t move, qboolean relink); + +void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg); +void SV_WriteClientdataToMessageFPM (edict_FPM_t *ent, sizebuf_t *msg); + +void SV_MoveToGoal (void); +void SV_MoveToGoalFPM (void); + +void SV_CheckForNewClients (void); +void SV_RunClients (void); +void SV_SaveSpawnparms (); +void SV_SaveSpawnparmsFPM (); +#ifdef QUAKE2 +void SV_SpawnServer (char *server, char *startspot); +void SV_SpawnServerFPM (char *server, char *startspot); +#else +void SV_SpawnServer (char *server); +void SV_SpawnServerFPM (char *server); +#endif diff --git a/project/jni/application/quake/source/slist.c b/project/jni/application/quake/source/slist.c new file mode 100644 index 000000000..2149585ba --- /dev/null +++ b/project/jni/application/quake/source/slist.c @@ -0,0 +1,128 @@ +#include "quakedef.h" + +server_entry_t slist[MAX_SERVER_LIST]; + +void SList_Init (void) { + memset (&slist, 0, sizeof(slist)); +} + +void SList_Shutdown (void) { + FILE *f; + + if (!(f = fopen (va("servers.cfg", com_gamedir), "wt"))) + { + Con_DPrintf ("Couldn't open servers.cfg\n"); + return; + } + SList_Save (f); + fclose (f); +} + +void SList_Set (int i, char *addr, char *desc) +{ + if (i >= MAX_SERVER_LIST || i < 0) + Sys_Error ("SList_Set: Bad index %d", i); + + if (slist[i].server) + Z_Free (slist[i].server); + if (slist[i].description) + Z_Free (slist[i].description); + + slist[i].server = CopyString (addr); + slist[i].description = CopyString (desc); +} + +void SList_Reset_NoFree (int i) +{ + if (i >= MAX_SERVER_LIST || i < 0) + Sys_Error ("SList_Reset_NoFree: Bad index %d", i); + + slist[i].description = slist[i].server = NULL; +} + +void SList_Reset (int i) +{ + if (i >= MAX_SERVER_LIST || i < 0) + Sys_Error ("SList_Reset: Bad index %d", i); + + if (slist[i].server) + { + Z_Free (slist[i].server); + slist[i].server = NULL; + } + + if (slist[i].description) + { + Z_Free (slist[i].description); + slist[i].description = NULL; + } +} + +void SList_Switch (int a, int b) +{ + server_entry_t temp; + + if (a >= MAX_SERVER_LIST || a < 0) + Sys_Error ("SList_Switch: Bad index %d", a); + if (b >= MAX_SERVER_LIST || b < 0) + Sys_Error ("SList_Switch: Bad index %d", b); + + memcpy (&temp, &slist[a], sizeof(temp)); + memcpy (&slist[a], &slist[b], sizeof(temp)); + memcpy (&slist[b], &temp, sizeof(temp)); +} + +int SList_Length (void) { + int count; + + for (count = 0 ; count < MAX_SERVER_LIST && slist[count].server ; count++); + + return count; +} + +void SList_Load (void) { + int c, len, argc, count; + char line[128], *desc, *addr; + FILE *f; + + if (!(f = fopen (va("servers.cfg", com_gamedir), "rt"))) + return; + + count = len = 0; + while ((c = getc(f))) { + if (c == '\n' || c == '\r' || c == EOF) { + if (c == '\r' && (c = getc(f)) != '\n' && c != EOF) + ungetc (c, f); + + line[len] = 0; + len = 0; + Cmd_TokenizeString (line); + + if ((argc = Cmd_Argc()) >= 1) { + addr = Cmd_Argv(0); + desc = (argc >= 2) ? Cmd_Args() : "Unknown"; + SList_Set (count, addr, desc); + if (++count == MAX_SERVER_LIST) + break; + } + if (c == EOF) + break; + } else { + if (len + 1 < sizeof(line)) + line[len++] = c; + } + } + + fclose (f); +} + +void SList_Save (FILE *f) { + int i; + + for (i = 0; i < MAX_SERVER_LIST; i++) { + if (!slist[i].server) + break; + + fprintf (f, "%s\t%s\n", slist[i].server, slist[i].description); + } +} diff --git a/project/jni/application/quake/source/slist.h b/project/jni/application/quake/source/slist.h new file mode 100644 index 000000000..c95d97ed9 --- /dev/null +++ b/project/jni/application/quake/source/slist.h @@ -0,0 +1,39 @@ +/* +Copyright (C) 1999-2000, contributors of the QuakeForge project + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// cl_slist.h + +#define MAX_SERVER_LIST 256 + +typedef struct { + char *server; + char *description; +} server_entry_t; + +extern server_entry_t slist[MAX_SERVER_LIST]; + +void SList_Init (void); +void SList_Shutdown (void); +void SList_Set (int i,char *addr,char *desc); +void SList_Reset_NoFree (int i); +void SList_Reset (int i); +void SList_Switch (int a,int b); +int SList_Length (void); +void SList_Load (void); +void SList_Save (FILE *f); diff --git a/project/jni/application/quake/source/snd_dma.c b/project/jni/application/quake/source/snd_dma.c new file mode 100644 index 000000000..c3dc4fafb --- /dev/null +++ b/project/jni/application/quake/source/snd_dma.c @@ -0,0 +1,1022 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// snd_dma.c -- main control for any streaming sound output device + +#include "quakedef.h" + +#ifdef _WIN32 +#include "winquake.h" +#endif + +void S_Play(void); +void S_PlayVol(void); +void S_SoundList(void); +void S_Update_(); +void S_StopAllSounds(qboolean clear); +void S_StopAllSoundsC(void); + +// ======================================================================= +// Internal sound data & structures +// ======================================================================= + +channel_t channels[MAX_CHANNELS]; +int total_channels; + +int snd_blocked = 0; +static qboolean snd_ambient = 1; +qboolean snd_initialized = false; + +// pointer should go away +volatile dma_t *shm = 0; +volatile dma_t sn; + +vec3_t listener_origin; +vec3_t listener_forward; +vec3_t listener_right; +vec3_t listener_up; +vec_t sound_nominal_clip_dist=1000.0; + +int soundtime; // sample PAIRS +int paintedtime; // sample PAIRS + + +#define MAX_SFX 512 +sfx_t *known_sfx; // hunk allocated [MAX_SFX] +int num_sfx; + +sfx_t *ambient_sfx[NUM_AMBIENTS]; + +int desired_speed = 22050; +int desired_bits = 16; + +int sound_started=0; + +cvar_t bgmvolume = {"bgmvolume", "1", true}; +cvar_t volume = {"volume", "0.7", true}; + +cvar_t nosound = {"nosound", "0"}; +cvar_t precache = {"precache", "1"}; +cvar_t loadas8bit = {"loadas8bit", "0"}; +cvar_t bgmbuffer = {"bgmbuffer", "4096"}; +cvar_t ambient_level = {"ambient_level", "0.3"}; +cvar_t ambient_fade = {"ambient_fade", "100"}; +cvar_t snd_noextraupdate = {"snd_noextraupdate", "0"}; +cvar_t snd_show = {"snd_show", "0"}; +cvar_t _snd_mixahead = {"_snd_mixahead", "0.1", true}; + + +// ==================================================================== +// User-setable variables +// ==================================================================== + + +// +// Fake dma is a synchronous faking of the DMA progress used for +// isolating performance in the renderer. The fakedma_updates is +// number of times S_Update() is called per second. +// + +qboolean fakedma = false; +int fakedma_updates = 15; + + +void S_AmbientOff (void) +{ + snd_ambient = false; +} + + +void S_AmbientOn (void) +{ + snd_ambient = true; +} + + +void S_SoundInfo_f(void) +{ + if (!sound_started || !shm) + { + Con_Printf ("sound system not started\n"); + return; + } + + Con_Printf("%5d stereo\n", shm->channels - 1); + Con_Printf("%5d samples\n", shm->samples); + Con_Printf("%5d samplepos\n", shm->samplepos); + Con_Printf("%5d samplebits\n", shm->samplebits); + Con_Printf("%5d submission_chunk\n", shm->submission_chunk); + Con_Printf("%5d speed\n", shm->speed); + Con_Printf("0x%x dma buffer\n", shm->buffer); + Con_Printf("%5d total_channels\n", total_channels); +} + + +/* +================ +S_Startup +================ +*/ + +void S_Startup (void) +{ + int rc; + + if (!snd_initialized) + return; + + if (!fakedma) + { + rc = SNDDMA_Init(); + + if (!rc) + { +#ifndef _WIN32 + Con_Printf("S_Startup: SNDDMA_Init failed.\n"); +#endif + sound_started = 0; + return; + } + } + + sound_started = 1; +} + + +/* +================ +S_Init +================ +*/ +void S_Init (void) +{ + + Con_Printf("\nSound Initialization\n"); + + if (COM_CheckParm("-nosound")) + return; + + if (COM_CheckParm("-simsound")) + fakedma = true; + + Cmd_AddCommand("play", S_Play); + Cmd_AddCommand("playvol", S_PlayVol); + Cmd_AddCommand("stopsound", S_StopAllSoundsC); + Cmd_AddCommand("soundlist", S_SoundList); + Cmd_AddCommand("soundinfo", S_SoundInfo_f); + + Cvar_RegisterVariable(&nosound); + Cvar_RegisterVariable(&volume); + Cvar_RegisterVariable(&precache); + Cvar_RegisterVariable(&loadas8bit); + Cvar_RegisterVariable(&bgmvolume); + Cvar_RegisterVariable(&bgmbuffer); + Cvar_RegisterVariable(&ambient_level); + Cvar_RegisterVariable(&ambient_fade); + Cvar_RegisterVariable(&snd_noextraupdate); + Cvar_RegisterVariable(&snd_show); + Cvar_RegisterVariable(&_snd_mixahead); + + if (host_parms.memsize < 0x800000) + { + Cvar_Set ("loadas8bit", "1"); + Con_Printf ("loading all sounds as 8bit\n"); + } + + + + snd_initialized = true; + + S_Startup (); + + SND_InitScaletable (); + + known_sfx = Hunk_AllocName (MAX_SFX*sizeof(sfx_t), "sfx_t"); + num_sfx = 0; + +// create a piece of DMA memory + + if (fakedma) + { + shm = (void *) Hunk_AllocName(sizeof(*shm), "shm"); + shm->splitbuffer = 0; + shm->samplebits = 16; + shm->speed = 22050; + shm->channels = 2; + shm->samples = 32768; + shm->samplepos = 0; + shm->soundalive = true; + shm->gamealive = true; + shm->submission_chunk = 1; + shm->buffer = Hunk_AllocName(1<<16, "shmbuf"); + } + + if ( shm ) { + Con_Printf ("Sound sampling rate: %i\n", shm->speed); + } + + // provides a tick sound until washed clean + +// if (shm->buffer) +// shm->buffer[4] = shm->buffer[5] = 0x7f; // force a pop for debugging + + ambient_sfx[AMBIENT_WATER] = S_PrecacheSound ("ambience/water1.wav"); + ambient_sfx[AMBIENT_SKY] = S_PrecacheSound ("ambience/wind2.wav"); + + S_StopAllSounds (true); +} + + +// ======================================================================= +// Shutdown sound engine +// ======================================================================= + +void S_Shutdown(void) +{ + + if (!sound_started) + return; + + if (shm) + shm->gamealive = 0; + + shm = 0; + sound_started = 0; + + if (!fakedma) + { + SNDDMA_Shutdown(); + } +} + + +// ======================================================================= +// Load a sound +// ======================================================================= + +/* +================== +S_FindName + +================== +*/ +sfx_t *S_FindName (char *name) +{ + int i; + sfx_t *sfx; + + if (!name) + Sys_Error ("S_FindName: NULL\n"); + + if (Q_strlen(name) >= MAX_QPATH) + Sys_Error ("Sound name too long: %s", name); + +// see if already loaded + for (i=0 ; i < num_sfx ; i++) + if (!Q_strcmp(known_sfx[i].name, name)) + { + return &known_sfx[i]; + } + + if (num_sfx == MAX_SFX) + Sys_Error ("S_FindName: out of sfx_t"); + + sfx = &known_sfx[i]; + strcpy (sfx->name, name); + + num_sfx++; + + return sfx; +} + + +/* +================== +S_TouchSound + +================== +*/ +void S_TouchSound (char *name) +{ + sfx_t *sfx; + + if (!sound_started) + return; + + sfx = S_FindName (name); + Cache_Check (&sfx->cache); +} + +/* +================== +S_PrecacheSound + +================== +*/ +sfx_t *S_PrecacheSound (char *name) +{ + sfx_t *sfx; + + if (!sound_started || nosound.value) + return NULL; + + sfx = S_FindName (name); + +// cache it in + if (precache.value) + S_LoadSound (sfx); + + return sfx; +} + + +//============================================================================= + +/* +================= +SND_PickChannel +================= +*/ +channel_t *SND_PickChannel(int entnum, int entchannel) +{ + int ch_idx; + int first_to_die; + int life_left; + +// Check for replacement sound, or find the best one to replace + first_to_die = -1; + life_left = 0x7fffffff; + for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++) + { + if (entchannel != 0 // channel 0 never overrides + && channels[ch_idx].entnum == entnum + && (channels[ch_idx].entchannel == entchannel || entchannel == -1) ) + { // allways override sound from same entity + first_to_die = ch_idx; + break; + } + + // don't let monster sounds override player sounds + if (channels[ch_idx].entnum == cl.viewentity && entnum != cl.viewentity && channels[ch_idx].sfx) + continue; + + if (channels[ch_idx].end - paintedtime < life_left) + { + life_left = channels[ch_idx].end - paintedtime; + first_to_die = ch_idx; + } + } + + if (first_to_die == -1) + return NULL; + + if (channels[first_to_die].sfx) + channels[first_to_die].sfx = NULL; + + return &channels[first_to_die]; +} + +/* +================= +SND_Spatialize +================= +*/ +void SND_Spatialize(channel_t *ch) +{ + vec_t dot; + vec_t ldist, rdist, dist; + vec_t lscale, rscale, scale; + vec3_t source_vec; + sfx_t *snd; + +// anything coming from the view entity will allways be full volume + if (ch->entnum == cl.viewentity) + { + ch->leftvol = ch->master_vol; + ch->rightvol = ch->master_vol; + return; + } + +// calculate stereo seperation and distance attenuation + + snd = ch->sfx; + VectorSubtract(ch->origin, listener_origin, source_vec); + + dist = VectorNormalize(source_vec) * ch->dist_mult; + + dot = DotProduct(listener_right, source_vec); + + if (shm->channels == 1) + { + rscale = 1.0; + lscale = 1.0; + } + else + { + rscale = 1.0 + dot; + lscale = 1.0 - dot; + } + +// add in distance effect + scale = (1.0 - dist) * rscale; + ch->rightvol = (int) (ch->master_vol * scale); + if (ch->rightvol < 0) + ch->rightvol = 0; + + scale = (1.0 - dist) * lscale; + ch->leftvol = (int) (ch->master_vol * scale); + if (ch->leftvol < 0) + ch->leftvol = 0; +} + + +// ======================================================================= +// Start a sound effect +// ======================================================================= + +void S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation) +{ + channel_t *target_chan, *check; + sfxcache_t *sc; + int vol; + int ch_idx; + int skip; + + if (!sound_started) + return; + + if (!sfx) + return; + + if (nosound.value) + return; + + vol = fvol*255; + +// pick a channel to play on + target_chan = SND_PickChannel(entnum, entchannel); + if (!target_chan) + return; + +// spatialize + memset (target_chan, 0, sizeof(*target_chan)); + VectorCopy(origin, target_chan->origin); + target_chan->dist_mult = attenuation / sound_nominal_clip_dist; + target_chan->master_vol = vol; + target_chan->entnum = entnum; + target_chan->entchannel = entchannel; + SND_Spatialize(target_chan); + + if (!target_chan->leftvol && !target_chan->rightvol) + return; // not audible at all + +// new channel + sc = S_LoadSound (sfx); + if (!sc) + { + target_chan->sfx = NULL; + return; // couldn't load the sound's data + } + + target_chan->sfx = sfx; + target_chan->pos = 0.0; + target_chan->end = paintedtime + sc->length; + +// if an identical sound has also been started this frame, offset the pos +// a bit to keep it from just making the first one louder + check = &channels[NUM_AMBIENTS]; + for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++) + { + if (check == target_chan) + continue; + if (check->sfx == sfx && !check->pos) + { + skip = rand () % (int)(0.1*shm->speed); + if (skip >= target_chan->end) + skip = target_chan->end - 1; + target_chan->pos += skip; + target_chan->end -= skip; + break; + } + + } +} + +void S_StopSound(int entnum, int entchannel) +{ + int i; + + for (i=0 ; ibuffer && !pDSBuf)) +#else + if (!sound_started || !shm || !shm->buffer) +#endif + return; + + if (shm->samplebits == 8) + clear = 0x80; + else + clear = 0; + +#ifdef _WIN32 + if (pDSBuf) + { + DWORD dwSize; + DWORD *pData; + int reps; + HRESULT hresult; + + reps = 0; + + while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pData, &dwSize, NULL, NULL, 0)) != DS_OK) + { + if (hresult != DSERR_BUFFERLOST) + { + Con_Printf ("S_ClearBuffer: DS::Lock Sound Buffer Failed\n"); + S_Shutdown (); + return; + } + + if (++reps > 10000) + { + Con_Printf ("S_ClearBuffer: DS: couldn't restore buffer\n"); + S_Shutdown (); + return; + } + } + + Q_memset(pData, clear, shm->samples * shm->samplebits/8); + + pDSBuf->lpVtbl->Unlock(pDSBuf, pData, dwSize, NULL, 0); + + } + else +#endif + { + Q_memset(shm->buffer, clear, shm->samples * shm->samplebits/8); + } +} + + +/* +================= +S_StaticSound +================= +*/ +void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation) +{ + channel_t *ss; + sfxcache_t *sc; + + if (!sfx) + return; + + if (total_channels == MAX_CHANNELS) + { + Con_Printf ("total_channels == MAX_CHANNELS\n"); + return; + } + + ss = &channels[total_channels]; + total_channels++; + + sc = S_LoadSound (sfx); + if (!sc) + return; + + if (sc->loopstart == -1) + { + Con_Printf ("Sound %s not looped\n", sfx->name); + return; + } + + ss->sfx = sfx; + VectorCopy (origin, ss->origin); + ss->master_vol = vol; + ss->dist_mult = (attenuation/64) / sound_nominal_clip_dist; + ss->end = paintedtime + sc->length; + + SND_Spatialize (ss); +} + + +//============================================================================= + +/* +=================== +S_UpdateAmbientSounds +=================== +*/ +void S_UpdateAmbientSounds (void) +{ + mleaf_t *l; + float vol; + int ambient_channel; + channel_t *chan; + + if (!snd_ambient) + return; + +// calc ambient sound levels + if (!cl.worldmodel) + return; + + l = Mod_PointInLeaf (listener_origin, cl.worldmodel); + if (!l || !ambient_level.value) + { + for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++) + channels[ambient_channel].sfx = NULL; + return; + } + + for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++) + { + chan = &channels[ambient_channel]; + chan->sfx = ambient_sfx[ambient_channel]; + + vol = ambient_level.value * l->ambient_sound_level[ambient_channel]; + if (vol < 8) + vol = 0; + + // don't adjust volume too fast + if (chan->master_vol < vol) + { + chan->master_vol += host_frametime * ambient_fade.value; + if (chan->master_vol > vol) + chan->master_vol = vol; + } + else if (chan->master_vol > vol) + { + chan->master_vol -= host_frametime * ambient_fade.value; + if (chan->master_vol < vol) + chan->master_vol = vol; + } + + chan->leftvol = chan->rightvol = chan->master_vol; + } +} + + +/* +============ +S_Update + +Called once each time through the main loop +============ +*/ +void S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up) +{ + int i, j; + int total; + channel_t *ch; + channel_t *combine; + + if (!sound_started || (snd_blocked > 0)) + return; + + VectorCopy(origin, listener_origin); + VectorCopy(forward, listener_forward); + VectorCopy(right, listener_right); + VectorCopy(up, listener_up); + +// update general area ambient sound sources + S_UpdateAmbientSounds (); + + combine = NULL; + +// update spatialization for static and dynamic sounds + ch = channels+NUM_AMBIENTS; + for (i=NUM_AMBIENTS ; isfx) + continue; + SND_Spatialize(ch); // respatialize channel + if (!ch->leftvol && !ch->rightvol) + continue; + + // try to combine static sounds with a previous channel of the same + // sound effect so we don't mix five torches every frame + + if (i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS) + { + // see if it can just use the last one + if (combine && combine->sfx == ch->sfx) + { + combine->leftvol += ch->leftvol; + combine->rightvol += ch->rightvol; + ch->leftvol = ch->rightvol = 0; + continue; + } + // search for one + combine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS; + for (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; jsfx == ch->sfx) + break; + + if (j == total_channels) + { + combine = NULL; + } + else + { + if (combine != ch) + { + combine->leftvol += ch->leftvol; + combine->rightvol += ch->rightvol; + ch->leftvol = ch->rightvol = 0; + } + continue; + } + } + + + } + +// +// debugging output +// + if (snd_show.value) + { + total = 0; + ch = channels; + for (i=0 ; isfx && (ch->leftvol || ch->rightvol) ) + { + //Con_Printf ("%3i %3i %s\n", ch->leftvol, ch->rightvol, ch->sfx->name); + total++; + } + + Con_Printf ("----(%i)----\n", total); + } + +// mix some sound + S_Update_(); +} + +void GetSoundtime(void) +{ + int samplepos; + static int buffers; + static int oldsamplepos; + int fullsamples; + + fullsamples = shm->samples / shm->channels; + +// it is possible to miscount buffers if it has wrapped twice between +// calls to S_Update. Oh well. +#ifdef __sun__ + soundtime = SNDDMA_GetSamples(); +#else + samplepos = SNDDMA_GetDMAPos(); + + + if (samplepos < oldsamplepos) + { + buffers++; // buffer wrapped + + if (paintedtime > 0x40000000) + { // time to chop things off to avoid 32 bit limits + buffers = 0; + paintedtime = fullsamples; + S_StopAllSounds (true); + } + } + oldsamplepos = samplepos; + + soundtime = buffers*fullsamples + samplepos/shm->channels; +#endif +} + +void S_ExtraUpdate (void) +{ + +#ifdef _WIN32 + IN_Accumulate (); +#endif + + if (snd_noextraupdate.value) + return; // don't pollute timings + S_Update_(); +} + +void S_Update_(void) +{ +#ifndef SDL + + unsigned endtime; + int samps; + + if (!sound_started || (snd_blocked > 0)) + return; + +// Updates DMA time + GetSoundtime(); + +// check to make sure that we haven't overshot + if (paintedtime < soundtime) + { + //Con_Printf ("S_Update_ : overflow\n"); + paintedtime = soundtime; + } + +// mix ahead of current position + endtime = soundtime + _snd_mixahead.value * shm->speed; + samps = shm->samples >> (shm->channels-1); + if (endtime - soundtime > samps) + endtime = soundtime + samps; + +#ifdef _WIN32 +// if the buffer was lost or stopped, restore it and/or restart it + { + DWORD dwStatus; + + if (pDSBuf) + { + if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DD_OK) + Con_Printf ("Couldn't get sound buffer status\n"); + + if (dwStatus & DSBSTATUS_BUFFERLOST) + pDSBuf->lpVtbl->Restore (pDSBuf); + + if (!(dwStatus & DSBSTATUS_PLAYING)) + pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING); + } + } +#endif + + S_PaintChannels (endtime); + + SNDDMA_Submit (); +#endif /* ! SDL */ +} + +/* +=============================================================================== + +console functions + +=============================================================================== +*/ + +void S_Play(void) +{ + static int hash=345; + int i; + char name[256]; + sfx_t *sfx; + + i = 1; + while (icache); + if (!sc) + continue; + size = sc->length*sc->width*(sc->stereo+1); + total += size; + if (sc->loopstart >= 0) + Con_Printf ("L"); + else + Con_Printf (" "); + Con_Printf("(%2db) %6i : %s\n",sc->width*8, size, sfx->name); + } + Con_Printf ("Total resident: %i\n", total); +} + + +void S_LocalSound (char *sound) +{ + sfx_t *sfx; + + if (nosound.value) + return; + if (!sound_started) + return; + + sfx = S_PrecacheSound (sound); + if (!sfx) + { + Con_Printf ("S_LocalSound: can't cache %s\n", sound); + return; + } + S_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1); +} + + +void S_ClearPrecache (void) +{ +} + + +void S_BeginPrecaching (void) +{ +} + + +void S_EndPrecaching (void) +{ +} + diff --git a/project/jni/application/quake/source/snd_mem.c b/project/jni/application/quake/source/snd_mem.c new file mode 100644 index 000000000..71e32aa05 --- /dev/null +++ b/project/jni/application/quake/source/snd_mem.c @@ -0,0 +1,341 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// snd_mem.c: sound caching + +#include "quakedef.h" + +int cache_full_cycle; + +byte *S_Alloc (int size); + +/* +================ +ResampleSfx +================ +*/ +void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data) +{ + int outcount; + int srcsample; + float stepscale; + int i; + int sample, samplefrac, fracstep; + sfxcache_t *sc; + + sc = Cache_Check (&sfx->cache); + if (!sc) + return; + + stepscale = (float)inrate / shm->speed; // this is usually 0.5, 1, or 2 + + outcount = sc->length / stepscale; + sc->length = outcount; + if (sc->loopstart != -1) + sc->loopstart = sc->loopstart / stepscale; + + sc->speed = shm->speed; + if (loadas8bit.value) + sc->width = 1; + else + sc->width = inwidth; + sc->stereo = 0; + +// resample / decimate to the current source rate + + if (stepscale == 1 && inwidth == 1 && sc->width == 1) + { +// fast special case + for (i=0 ; idata)[i] + = (int)( (unsigned char)(data[i]) - 128); + } + else + { +// general case + samplefrac = 0; + fracstep = stepscale*256; + for (i=0 ; i> 8; + samplefrac += fracstep; + if (inwidth == 2) + sample = LittleShort ( ((short *)data)[srcsample] ); + else + sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8; + if (sc->width == 2) + ((short *)sc->data)[i] = sample; + else + ((signed char *)sc->data)[i] = sample >> 8; + } + } +} + +//============================================================================= + +/* +============== +S_LoadSound +============== +*/ +sfxcache_t *S_LoadSound (sfx_t *s) +{ + char namebuffer[256]; + byte *data; + wavinfo_t info; + int len; + float stepscale; + sfxcache_t *sc; + byte stackbuf[1*1024]; // avoid dirtying the cache heap + +// see if still in memory + sc = Cache_Check (&s->cache); + if (sc) + return sc; + +//Con_Printf ("S_LoadSound: %x\n", (int)stackbuf); +// load it in + Q_strcpy(namebuffer, "sound/"); + Q_strcat(namebuffer, s->name); + +// Con_Printf ("loading %s\n",namebuffer); + + data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf)); + + if (!data) + { + Con_Printf ("Couldn't load %s\n", namebuffer); + return NULL; + } + + info = GetWavinfo (s->name, data, com_filesize); + if (info.channels != 1) + { + Con_Printf ("%s is a stereo sample\n",s->name); + return NULL; + } + + stepscale = (float)info.rate / shm->speed; + len = info.samples / stepscale; + + len = len * info.width * info.channels; + + sc = Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name); + if (!sc) + return NULL; + + sc->length = info.samples; + sc->loopstart = info.loopstart; + sc->speed = info.rate; + sc->width = info.width; + sc->stereo = info.channels; + + ResampleSfx (s, sc->speed, sc->width, data + info.dataofs); + + return sc; +} + + + +/* +=============================================================================== + +WAV loading + +=============================================================================== +*/ + + +byte *data_p; +byte *iff_end; +byte *last_chunk; +byte *iff_data; +int iff_chunk_len; + + +short GetLittleShort(void) +{ + short val = 0; + val = *data_p; + val = val + (*(data_p+1)<<8); + data_p += 2; + return val; +} + +int GetLittleLong(void) +{ + int val = 0; + val = *data_p; + val = val + (*(data_p+1)<<8); + val = val + (*(data_p+2)<<16); + val = val + (*(data_p+3)<<24); + data_p += 4; + return val; +} + +void FindNextChunk(char *name) +{ + while (1) + { + data_p=last_chunk; + + if (data_p >= iff_end) + { // didn't find the chunk + data_p = NULL; + return; + } + + data_p += 4; + iff_chunk_len = GetLittleLong(); + if (iff_chunk_len < 0) + { + data_p = NULL; + return; + } +// if (iff_chunk_len > 1024*1024) +// Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len); + data_p -= 8; + last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 ); + if (!Q_strncmp(data_p, name, 4)) + return; + } +} + +void FindChunk(char *name) +{ + last_chunk = iff_data; + FindNextChunk (name); +} + + +void DumpChunks(void) +{ + char str[5]; + + str[4] = 0; + data_p=iff_data; + do + { + memcpy (str, data_p, 4); + data_p += 4; + iff_chunk_len = GetLittleLong(); + Con_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len); + data_p += (iff_chunk_len + 1) & ~1; + } while (data_p < iff_end); +} + +/* +============ +GetWavinfo +============ +*/ +wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength) +{ + wavinfo_t info; + int i; + int format; + int samples; + + memset (&info, 0, sizeof(info)); + + if (!wav) + return info; + + iff_data = wav; + iff_end = wav + wavlength; + +// find "RIFF" chunk + FindChunk("RIFF"); + if (!(data_p && !Q_strncmp(data_p+8, "WAVE", 4))) + { + Con_Printf("Missing RIFF/WAVE chunks\n"); + return info; + } + +// get "fmt " chunk + iff_data = data_p + 12; +// DumpChunks (); + + FindChunk("fmt "); + if (!data_p) + { + Con_Printf("Missing fmt chunk\n"); + return info; + } + data_p += 8; + format = GetLittleShort(); + if (format != 1) + { + Con_Printf("Microsoft PCM format only\n"); + return info; + } + + info.channels = GetLittleShort(); + info.rate = GetLittleLong(); + data_p += 4+2; + info.width = GetLittleShort() / 8; + +// get cue chunk + FindChunk("cue "); + if (data_p) + { + data_p += 32; + info.loopstart = GetLittleLong(); +// Con_Printf("loopstart=%d\n", sfx->loopstart); + + // if the next chunk is a LIST chunk, look for a cue length marker + FindNextChunk ("LIST"); + if (data_p) + { + if (!strncmp (data_p + 28, "mark", 4)) + { // this is not a proper parse, but it works with cooledit... + data_p += 24; + i = GetLittleLong (); // samples in loop + info.samples = info.loopstart + i; +// Con_Printf("looped length: %i\n", i); + } + } + } + else + info.loopstart = -1; + +// find data chunk + FindChunk("data"); + if (!data_p) + { + Con_Printf("Missing data chunk\n"); + return info; + } + + data_p += 4; + samples = GetLittleLong () / info.width; + + if (info.samples) + { + if (samples < info.samples) + Sys_Error ("Sound %s has a bad loop length", name); + } + else + info.samples = samples; + + info.dataofs = data_p - wav; + + return info; +} + diff --git a/project/jni/application/quake/source/snd_mix.c b/project/jni/application/quake/source/snd_mix.c new file mode 100644 index 000000000..d31f6c992 --- /dev/null +++ b/project/jni/application/quake/source/snd_mix.c @@ -0,0 +1,398 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// snd_mix.c -- portable code to mix sounds for snd_dma.c + +#include "quakedef.h" + +#ifdef _WIN32 +#include "winquake.h" +#else +#define DWORD unsigned long +#endif + +#define PAINTBUFFER_SIZE 512 +portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE]; +int snd_scaletable[32][256]; +int *snd_p, snd_linear_count, snd_vol; +short *snd_out; + +void Snd_WriteLinearBlastStereo16 (void); + +#if !id386 +void Snd_WriteLinearBlastStereo16 (void) +{ + int i; + int val; + + for (i=0 ; i>8; + if (val > 0x7fff) + snd_out[i] = 0x7fff; + else if (val < (short)0x8000) + snd_out[i] = (short)0x8000; + else + snd_out[i] = val; + + val = (snd_p[i+1]*snd_vol)>>8; + if (val > 0x7fff) + snd_out[i+1] = 0x7fff; + else if (val < (short)0x8000) + snd_out[i+1] = (short)0x8000; + else + snd_out[i+1] = val; + } +} +#endif + +void S_TransferStereo16 (int endtime) +{ + int lpos; + int lpaintedtime; + DWORD *pbuf; +#ifdef _WIN32 + int reps; + DWORD dwSize,dwSize2; + DWORD *pbuf2; + HRESULT hresult; +#endif + + snd_vol = volume.value*256; + + snd_p = (int *) paintbuffer; + lpaintedtime = paintedtime; + +#ifdef _WIN32 + if (pDSBuf) + { + reps = 0; + + while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, + &pbuf2, &dwSize2, 0)) != DS_OK) + { + if (hresult != DSERR_BUFFERLOST) + { + Con_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n"); + S_Shutdown (); + S_Startup (); + return; + } + + if (++reps > 10000) + { + Con_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n"); + S_Shutdown (); + S_Startup (); + return; + } + } + } + else +#endif + { + pbuf = (DWORD *)shm->buffer; + } + + while (lpaintedtime < endtime) + { + // handle recirculating buffer issues + lpos = lpaintedtime & ((shm->samples>>1)-1); + + snd_out = (short *) pbuf + (lpos<<1); + + snd_linear_count = (shm->samples>>1) - lpos; + if (lpaintedtime + snd_linear_count > endtime) + snd_linear_count = endtime - lpaintedtime; + + snd_linear_count <<= 1; + + // write a linear blast of samples + Snd_WriteLinearBlastStereo16 (); + + snd_p += snd_linear_count; + lpaintedtime += (snd_linear_count>>1); + } + +#ifdef _WIN32 + if (pDSBuf) + pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0); +#endif +} + +void S_TransferPaintBuffer(int endtime) +{ + int out_idx; + int count; + int out_mask; + int *p; + int step; + int val; + int snd_vol; + DWORD *pbuf; +#ifdef _WIN32 + int reps; + DWORD dwSize,dwSize2; + DWORD *pbuf2; + HRESULT hresult; +#endif + + if (shm->samplebits == 16 && shm->channels == 2) + { + S_TransferStereo16 (endtime); + return; + } + + p = (int *) paintbuffer; + count = (endtime - paintedtime) * shm->channels; + out_mask = shm->samples - 1; + out_idx = paintedtime * shm->channels & out_mask; + step = 3 - shm->channels; + snd_vol = volume.value*256; + +#ifdef _WIN32 + if (pDSBuf) + { + reps = 0; + + while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, + &pbuf2,&dwSize2, 0)) != DS_OK) + { + if (hresult != DSERR_BUFFERLOST) + { + Con_Printf ("S_TransferPaintBuffer: DS::Lock Sound Buffer Failed\n"); + S_Shutdown (); + S_Startup (); + return; + } + + if (++reps > 10000) + { + Con_Printf ("S_TransferPaintBuffer: DS: couldn't restore buffer\n"); + S_Shutdown (); + S_Startup (); + return; + } + } + } + else +#endif + { + pbuf = (DWORD *)shm->buffer; + } + + if (shm->samplebits == 16) + { + short *out = (short *) pbuf; + while (count--) + { + val = (*p * snd_vol) >> 8; + p+= step; + if (val > 0x7fff) + val = 0x7fff; + else if (val < (short)0x8000) + val = (short)0x8000; + out[out_idx] = val; + out_idx = (out_idx + 1) & out_mask; + } + } + else if (shm->samplebits == 8) + { + unsigned char *out = (unsigned char *) pbuf; + while (count--) + { + val = (*p * snd_vol) >> 8; + p+= step; + if (val > 0x7fff) + val = 0x7fff; + else if (val < (short)0x8000) + val = (short)0x8000; + out[out_idx] = (val>>8) + 128; + out_idx = (out_idx + 1) & out_mask; + } + } + +#ifdef _WIN32 + if (pDSBuf) { + DWORD dwNewpos, dwWrite; + int il = paintedtime; + int ir = endtime - paintedtime; + + ir += il; + + pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0); + + pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &dwNewpos, &dwWrite); + +// if ((dwNewpos >= il) && (dwNewpos <= ir)) +// Con_Printf("%d-%d p %d c\n", il, ir, dwNewpos); + } +#endif +} + + +/* +=============================================================================== + +CHANNEL MIXING + +=============================================================================== +*/ + +void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime); +void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime); + +void S_PaintChannels(int endtime) +{ + int i; + int end; + channel_t *ch; + sfxcache_t *sc; + int ltime, count; + + while (paintedtime < endtime) + { + // if paintbuffer is smaller than DMA buffer + end = endtime; + if (endtime - paintedtime > PAINTBUFFER_SIZE) + end = paintedtime + PAINTBUFFER_SIZE; + + // clear the paint buffer + Q_memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t)); + + // paint in the channels. + ch = channels; + for (i=0; isfx) + continue; + if (!ch->leftvol && !ch->rightvol) + continue; + sc = S_LoadSound (ch->sfx); + if (!sc) + continue; + + ltime = paintedtime; + + while (ltime < end) + { // paint up to end + if (ch->end < end) + count = ch->end - ltime; + else + count = end - ltime; + + if (count > 0) + { + if (sc->width == 1) + SND_PaintChannelFrom8(ch, sc, count); + else + SND_PaintChannelFrom16(ch, sc, count); + + ltime += count; + } + + // if at end of loop, restart + if (ltime >= ch->end) + { + if (sc->loopstart >= 0) + { + ch->pos = sc->loopstart; + ch->end = ltime + sc->length - ch->pos; + } + else + { // channel just stopped + ch->sfx = NULL; + break; + } + } + } + + } + + // transfer out according to DMA format + S_TransferPaintBuffer(end); + paintedtime = end; + } +} + +void SND_InitScaletable (void) +{ + int i, j; + + for (i=0 ; i<32 ; i++) + for (j=0 ; j<256 ; j++) + snd_scaletable[i][j] = ((signed char)j) * i * 8; +} + + +#if !id386 + +void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count) +{ + int data; + int *lscale, *rscale; + unsigned char *sfx; + int i; + + if (ch->leftvol > 255) + ch->leftvol = 255; + if (ch->rightvol > 255) + ch->rightvol = 255; + + lscale = snd_scaletable[ch->leftvol >> 3]; + rscale = snd_scaletable[ch->rightvol >> 3]; + sfx = (signed char *)sc->data + ch->pos; + + for (i=0 ; ipos += count; +} + +#endif // !id386 + + +void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count) +{ + int data; + int left, right; + int leftvol, rightvol; + signed short *sfx; + int i; + + leftvol = ch->leftvol; + rightvol = ch->rightvol; + sfx = (signed short *)sc->data + ch->pos; + + for (i=0 ; i> 8; + right = (data * rightvol) >> 8; + paintbuffer[i].left += left; + paintbuffer[i].right += right; + } + + ch->pos += count; +} + diff --git a/project/jni/application/quake/source/snd_sdl.c b/project/jni/application/quake/source/snd_sdl.c new file mode 100644 index 000000000..3a563b738 --- /dev/null +++ b/project/jni/application/quake/source/snd_sdl.c @@ -0,0 +1,109 @@ +#include +#include "SDL_audio.h" +#include "SDL_byteorder.h" +#include "quakedef.h" + +static dma_t the_shm; +static int snd_inited; + +extern int desired_speed; +extern int desired_bits; + +static void paint_audio(void *unused, Uint8 *stream, int len) +{ + if ( shm ) { + shm->buffer = stream; + shm->samplepos += len/(shm->samplebits/8)/2; + // Check for samplepos overflow? + S_PaintChannels (shm->samplepos); + } +} + +qboolean SNDDMA_Init(void) { + SDL_AudioSpec desired, obtained; + + snd_inited = 0; + + /* Set up the desired format */ + desired.freq = desired_speed; + switch (desired_bits) { + case 8: + desired.format = AUDIO_U8; + break; + case 16: + if ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) + desired.format = AUDIO_S16MSB; + else + desired.format = AUDIO_S16LSB; + break; + default: + Con_Printf("Unknown number of audio bits: %d\n", + desired_bits); + return 0; + } + + desired.channels = 2; + desired.samples = 512; + desired.callback = paint_audio; + + /* Open the audio device */ + if ( SDL_OpenAudio(&desired, &obtained) < 0 ) { + Con_Printf("Couldn't open SDL audio: %s\n", SDL_GetError()); + return 0; + } + + /* Make sure we can support the audio format */ + switch (obtained.format) { + case AUDIO_U8: + /* Supported */ + break; + case AUDIO_S16SYS: + /* Supported */ + break; + /* case AUDIO_S16LSB: + case AUDIO_S16MSB: + if ( ((obtained.format == AUDIO_S16LSB) && (SDL_BYTEORDER == SDL_LIL_ENDIAN)) || ((obtained.format == AUDIO_S16MSB) && (SDL_BYTEORDER == SDL_BIG_ENDIAN)) ) { + break; + } */ + default: + /* Not supported -- force SDL to do our bidding */ + SDL_CloseAudio(); + if ( SDL_OpenAudio(&desired, NULL) < 0 ) { + Con_Printf("Couldn't open SDL audio: %s\n", + SDL_GetError()); + return 0; + } + memcpy(&obtained, &desired, sizeof(desired)); + break; + } + SDL_PauseAudio(0); + + /* Fill the audio DMA information block */ + shm = &the_shm; + shm->splitbuffer = 0; + shm->samplebits = (obtained.format & 0xFF); + shm->speed = obtained.freq; + shm->channels = obtained.channels; + shm->samples = obtained.samples*shm->channels; + shm->samplepos = 0; + shm->submission_chunk = 1; + shm->buffer = NULL; + + snd_inited = 1; + return 1; +} + +int SNDDMA_GetDMAPos(void) +{ + return shm->samplepos; +} + +void SNDDMA_Shutdown(void) +{ + if (snd_inited) + { + SDL_CloseAudio(); + snd_inited = 0; + } +} + diff --git a/project/jni/application/quake/source/sound.h b/project/jni/application/quake/source/sound.h new file mode 100644 index 000000000..1ba08d3f6 --- /dev/null +++ b/project/jni/application/quake/source/sound.h @@ -0,0 +1,177 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sound.h -- client sound i/o functions + +#ifndef __SOUND__ +#define __SOUND__ + +#define DEFAULT_SOUND_PACKET_VOLUME 255 +#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0 + +// !!! if this is changed, it much be changed in asm_i386.h too !!! +typedef struct +{ + int left; + int right; +} portable_samplepair_t; + +typedef struct sfx_s +{ + char name[MAX_QPATH]; + cache_user_t cache; +} sfx_t; + +// !!! if this is changed, it much be changed in asm_i386.h too !!! +typedef struct +{ + int length; + int loopstart; + int speed; + int width; + int stereo; + byte data[1]; // variable sized +} sfxcache_t; + +typedef struct +{ + qboolean gamealive; + qboolean soundalive; + qboolean splitbuffer; + int channels; + int samples; // mono samples in buffer + int submission_chunk; // don't mix less than this # + int samplepos; // in mono samples + int samplebits; + int speed; + unsigned char *buffer; +} dma_t; + +// !!! if this is changed, it much be changed in asm_i386.h too !!! +typedef struct +{ + sfx_t *sfx; // sfx number + int leftvol; // 0-255 volume + int rightvol; // 0-255 volume + int end; // end time in global paintsamples + int pos; // sample position in sfx + int looping; // where to loop, -1 = no looping + int entnum; // to allow overriding a specific sound + int entchannel; // + vec3_t origin; // origin of sound effect + vec_t dist_mult; // distance multiplier (attenuation/clipK) + int master_vol; // 0-255 master volume +} channel_t; + +typedef struct +{ + int rate; + int width; + int channels; + int loopstart; + int samples; + int dataofs; // chunk starts this many bytes from file start +} wavinfo_t; + +void S_Init (void); +void S_Startup (void); +void S_Shutdown (void); +void S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation); +void S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation); +void S_StopSound (int entnum, int entchannel); +void S_StopAllSounds(qboolean clear); +void S_ClearBuffer (void); +void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up); +void S_ExtraUpdate (void); + +sfx_t *S_PrecacheSound (char *sample); +void S_TouchSound (char *sample); +void S_ClearPrecache (void); +void S_BeginPrecaching (void); +void S_EndPrecaching (void); +void S_PaintChannels(int endtime); +void S_InitPaintChannels (void); + +// picks a channel based on priorities, empty slots, number of channels +channel_t *SND_PickChannel(int entnum, int entchannel); + +// spatializes a channel +void SND_Spatialize(channel_t *ch); + +// initializes cycling through a DMA buffer and returns information on it +qboolean SNDDMA_Init(void); + +// gets the current DMA position +int SNDDMA_GetDMAPos(void); + +// shutdown the DMA xfer. +void SNDDMA_Shutdown(void); + +// ==================================================================== +// User-setable variables +// ==================================================================== + +#define MAX_CHANNELS 128 +#define MAX_DYNAMIC_CHANNELS 8 + + +extern channel_t channels[MAX_CHANNELS]; +// 0 to MAX_DYNAMIC_CHANNELS-1 = normal entity sounds +// MAX_DYNAMIC_CHANNELS to MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS -1 = water, etc +// MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS to total_channels = static sounds + +extern int total_channels; + +// +// Fake dma is a synchronous faking of the DMA progress used for +// isolating performance in the renderer. The fakedma_updates is +// number of times S_Update() is called per second. +// + +extern qboolean fakedma; +extern int fakedma_updates; +extern int paintedtime; +extern vec3_t listener_origin; +extern vec3_t listener_forward; +extern vec3_t listener_right; +extern vec3_t listener_up; +extern volatile dma_t *shm; +extern volatile dma_t sn; +extern vec_t sound_nominal_clip_dist; + +extern cvar_t loadas8bit; +extern cvar_t bgmvolume; +extern cvar_t volume; + +extern qboolean snd_initialized; + +extern int snd_blocked; + +void S_LocalSound (char *s); +sfxcache_t *S_LoadSound (sfx_t *s); + +wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength); + +void SND_InitScaletable (void); +void SNDDMA_Submit(void); + +void S_AmbientOff (void); +void S_AmbientOn (void); + +#endif diff --git a/project/jni/application/quake/source/spritegn.h b/project/jni/application/quake/source/spritegn.h new file mode 100644 index 000000000..55cca0639 --- /dev/null +++ b/project/jni/application/quake/source/spritegn.h @@ -0,0 +1,110 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// +// spritegn.h: header file for sprite generation program +// + +// ********************************************************** +// * This file must be identical in the spritegen directory * +// * and in the Quake directory, because it's used to * +// * pass data from one to the other via .spr files. * +// ********************************************************** + +//------------------------------------------------------- +// This program generates .spr sprite package files. +// The format of the files is as follows: +// +// dsprite_t file header structure +// +// +// dspriteframe_t frame header structure +// sprite bitmap +// +// dspriteframe_t frame header structure +// sprite bitmap +// +//------------------------------------------------------- + +#ifdef INCLUDELIBS + +#include +#include +#include +#include + +//#include "cmdlib.h" +//#include "scriplib.h" +//#include "dictlib.h" +//#include "trilib.h" +//#include "lbmlib.h" +#include "mathlib.h" + +#endif + +#define SPRITE_VERSION 1 + +// must match definition in modelgen.h +#ifndef SYNCTYPE_T +#define SYNCTYPE_T +typedef enum {ST_SYNC=0, ST_RAND } synctype_t; +#endif + +// TODO: shorten these? +typedef struct { + int ident; + int version; + int type; + float boundingradius; + int width; + int height; + int numframes; + float beamlength; + synctype_t synctype; +} dsprite_t; + +#define SPR_VP_PARALLEL_UPRIGHT 0 +#define SPR_FACING_UPRIGHT 1 +#define SPR_VP_PARALLEL 2 +#define SPR_ORIENTED 3 +#define SPR_VP_PARALLEL_ORIENTED 4 + +typedef struct { + int origin[2]; + int width; + int height; +} dspriteframe_t; + +typedef struct { + int numframes; +} dspritegroup_t; + +typedef struct { + float interval; +} dspriteinterval_t; + +typedef enum { SPR_SINGLE=0, SPR_GROUP } spriteframetype_t; + +typedef struct { + spriteframetype_t type; +} dspriteframetype_t; + +#define IDSPRITEHEADER (('P'<<24)+('S'<<16)+('D'<<8)+'I') + // little-endian "IDSP" + diff --git a/project/jni/application/quake/source/sv_main.c b/project/jni/application/quake/source/sv_main.c new file mode 100644 index 000000000..1dd734ea7 --- /dev/null +++ b/project/jni/application/quake/source/sv_main.c @@ -0,0 +1,2208 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sv_main.c -- server main program + +#include "quakedef.h" + +server_t sv; +server_static_t svs; + +#ifdef USEFPM +server_FPM_t svFPM; +server_static_FPM_t svsFPM; +#endif //USEFPM + +char localmodels[MAX_MODELS][5]; // inline model names for precache + +//============================================================================ + +/* +=============== +SV_Init +=============== +*/ +void SV_Init (void) +{ + int i; + extern cvar_t sv_maxvelocity; + extern cvar_t sv_gravity; + extern cvar_t sv_nostep; + extern cvar_t sv_friction; + extern cvar_t sv_edgefriction; + extern cvar_t sv_stopspeed; + extern cvar_t sv_maxspeed; + extern cvar_t sv_accelerate; + extern cvar_t sv_idealpitchscale; + extern cvar_t sv_aim; + + Cvar_RegisterVariable (&sv_maxvelocity); + Cvar_RegisterVariable (&sv_gravity); + Cvar_RegisterVariable (&sv_friction); + Cvar_RegisterVariable (&sv_edgefriction); + Cvar_RegisterVariable (&sv_stopspeed); + Cvar_RegisterVariable (&sv_maxspeed); + Cvar_RegisterVariable (&sv_accelerate); + Cvar_RegisterVariable (&sv_idealpitchscale); + Cvar_RegisterVariable (&sv_aim); + Cvar_RegisterVariable (&sv_nostep); + + for (i=0 ; i MAX_DATAGRAM-16) + return; + MSG_WriteByte (&sv.datagram, svc_particle); + MSG_WriteCoord (&sv.datagram, org[0]); + MSG_WriteCoord (&sv.datagram, org[1]); + MSG_WriteCoord (&sv.datagram, org[2]); + for (i=0 ; i<3 ; i++) + { + v = (int)(dir[i]*16); + if (v > 127) + v = 127; + else if (v < -128) + v = -128; + MSG_WriteChar (&sv.datagram, v); + } + MSG_WriteByte (&sv.datagram, count); + MSG_WriteByte (&sv.datagram, color); +} + +#ifdef USEFPM +void SV_StartParticleFPM (vec3_FPM_t org, vec3_FPM_t dir, int color, int count) +{ + int i, v; + + if (svFPM.datagram.cursize > MAX_DATAGRAM-16) + return; + MSG_WriteByte (&svFPM.datagram, svc_particle); + MSG_WriteCoordFPM (&svFPM.datagram, org[0]); + MSG_WriteCoordFPM (&svFPM.datagram, org[1]); + MSG_WriteCoordFPM (&svFPM.datagram, org[2]); + for (i=0 ; i<3 ; i++) + { + v = FPM_TOLONG(FPM_MUL(dir[i],FPM_FROMLONGC(16))); + if (v > 127) + v = 127; + else if (v < -128) + v = -128; + MSG_WriteChar (&svFPM.datagram, v); + } + MSG_WriteByte (&svFPM.datagram, count); + MSG_WriteByte (&svFPM.datagram, color); +} +#endif //USEFPM + +/* +================== +SV_StartSound + +Each entity can have eight independant sound sources, like voice, +weapon, feet, etc. + +Channel 0 is an auto-allocate channel, the others override anything +allready running on that entity/channel pair. + +An attenuation of 0 will play full volume everywhere in the level. +Larger attenuations will drop off. (max 4 attenuation) + +================== +*/ +void SV_StartSound (edict_t *entity, int channel, char *sample, int volume, + float attenuation) +{ + int sound_num; + int field_mask; + int i; + int ent; + + if (volume < 0 || volume > 255) + Sys_Error ("SV_StartSound: volume = %i", volume); + + if (attenuation < 0 || attenuation > 4) + Sys_Error ("SV_StartSound: attenuation = %f", attenuation); + + if (channel < 0 || channel > 7) + Sys_Error ("SV_StartSound: channel = %i", channel); + + if (sv.datagram.cursize > MAX_DATAGRAM-16) + return; + +// find precache number for sound + for (sound_num=1 ; sound_numv.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]))); +} + +#ifdef USEFPM +void SV_StartSoundFPM (edict_FPM_t *entity, int channel, char *sample, int volume, + float attenuation) +{ + int sound_num; + int field_mask; + int i; + int ent; + + if (volume < 0 || volume > 255) + Sys_Error ("SV_StartSound: volume = %i", volume); + + if (attenuation < 0 || attenuation > 4) + Sys_Error ("SV_StartSound: attenuation = %f", attenuation); + + if (channel < 0 || channel > 7) + Sys_Error ("SV_StartSound: channel = %i", channel); + + if (svFPM.datagram.cursize > MAX_DATAGRAM-16) + return; + +// find precache number for sound + for (sound_num=1 ; sound_numv.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]))); +} +#endif //USEFPM + +/* +============================================================================== + +CLIENT SPAWNING + +============================================================================== +*/ + +/* +================ +SV_SendServerinfo + +Sends the first message from the server to a connected client. +This will be sent on the initial connection and upon each server load. +================ +*/ +void SV_SendServerinfo (client_t *client) { + char **s; + char message[2048]; + + MSG_WriteByte (&client->message, svc_print); + sprintf (message, "%c\nVERSION %4.2f SERVER (%i CRC)", 2, (float)GP2X_VERSION, pr_crc); + MSG_WriteString (&client->message,message); + + MSG_WriteByte (&client->message, svc_serverinfo); + MSG_WriteLong (&client->message, PROTOCOL_VERSION); + MSG_WriteByte (&client->message, svs.maxclients); + + if (!coop.value && deathmatch.value) + MSG_WriteByte (&client->message, GAME_DEATHMATCH); + else + MSG_WriteByte (&client->message, GAME_COOP); + + sprintf (message, pr_strings+sv.edicts->v.message); + + MSG_WriteString (&client->message,message); + + for (s = sv.model_precache+1 ; *s ; s++) + MSG_WriteString (&client->message, *s); + MSG_WriteByte (&client->message, 0); + + for (s = sv.sound_precache+1 ; *s ; s++) + MSG_WriteString (&client->message, *s); + MSG_WriteByte (&client->message, 0); + +// send music + MSG_WriteByte (&client->message, svc_cdtrack); + MSG_WriteByte (&client->message, (int)sv.edicts->v.sounds); + MSG_WriteByte (&client->message, (int)sv.edicts->v.sounds); + +// set view + MSG_WriteByte (&client->message, svc_setview); + MSG_WriteShort (&client->message, NUM_FOR_EDICT(client->edict)); + + MSG_WriteByte (&client->message, svc_signonnum); + MSG_WriteByte (&client->message, 1); + + client->sendsignon = true; + client->spawned = false; // need prespawn, spawn, etc +} + +#ifdef USEFPM +void SV_SendServerinfoFPM (client_FPM_t *client) +{ + char **s; + char message[2048]; + + + MSG_WriteByte (&client->message, svc_print); + sprintf (message, "%c\nVERSION %4.2f SERVER (%i CRC)", 2, VERSION, pr_crc); + MSG_WriteString (&client->message,message); + + MSG_WriteByte (&client->message, svc_serverinfo); + MSG_WriteLong (&client->message, PROTOCOL_VERSION); + MSG_WriteByte (&client->message, svs.maxclients); + + if (!coop.value && deathmatch.value) + MSG_WriteByte (&client->message, GAME_DEATHMATCH); + else + MSG_WriteByte (&client->message, GAME_COOP); + + sprintf (message, pr_strings+svFPM.edicts->v.message); + + MSG_WriteString (&client->message,message); + + for (s = svFPM.model_precache+1 ; *s ; s++) + MSG_WriteString (&client->message, *s); + MSG_WriteByte (&client->message, 0); + + for (s = svFPM.sound_precache+1 ; *s ; s++) + MSG_WriteString (&client->message, *s); + MSG_WriteByte (&client->message, 0); + +// send music + MSG_WriteByte (&client->message, svc_cdtrack); + MSG_WriteByte (&client->message, (int)svFPM.edicts->v.sounds); + MSG_WriteByte (&client->message, (int)svFPM.edicts->v.sounds); + +// set view + MSG_WriteByte (&client->message, svc_setview); + MSG_WriteShort (&client->message, NUM_FOR_EDICTFPM(client->edict)); + + MSG_WriteByte (&client->message, svc_signonnum); + MSG_WriteByte (&client->message, 1); + + client->sendsignon = true; + client->spawned = false; // need prespawn, spawn, etc +} +#endif //USEFPM + +/* +================ +SV_ConnectClient + +Initializes a client_t for a new net connection. This will only be called +once for a player each game, not once for each level change. +================ +*/ +void SV_ConnectClient (int clientnum) +{ + edict_t *ent; + client_t *client; + int edictnum; + struct qsocket_s *netconnection; + int i; + float spawn_parms[NUM_SPAWN_PARMS]; + + client = svs.clients + clientnum; + + Con_DPrintf ("Client %s connected\n", client->netconnection->address); + + edictnum = clientnum+1; + + ent = EDICT_NUM(edictnum); + +// set up the client_t + netconnection = client->netconnection; + + if (sv.loadgame) + Q_memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms)); + Q_memset (client, 0, sizeof(*client)); + client->netconnection = netconnection; + + strcpy (client->name, "unconnected"); + client->active = true; + client->spawned = false; + client->edict = ent; + client->message.data = client->msgbuf; + client->message.maxsize = sizeof(client->msgbuf); + client->message.allowoverflow = true; // we can catch it + +#ifdef IDGODS + client->privileged = IsID(&client->netconnection->addr); +#else + client->privileged = false; +#endif + + if (sv.loadgame) + Q_memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms)); + else + { + // call the progs to get default spawn parms for the new client + PR_ExecuteProgram (pr_global_struct->SetNewParms); + for (i=0 ; ispawn_parms[i] = (&pr_global_struct->parm1)[i]; + } + + SV_SendServerinfo (client); +} + +#ifdef USEFPM +void SV_ConnectClientFPM (int clientnum) +{ + edict_FPM_t *ent; + client_FPM_t *client; + int edictnum; + struct qsocket_s *netconnection; + int i; + float spawn_parms[NUM_SPAWN_PARMS]; + + client = svsFPM.clients + clientnum; + + Con_DPrintf ("Client %s connected\n", client->netconnection->address); + + edictnum = clientnum+1; + + ent = EDICT_NUMFPM(edictnum); + +// set up the client_t + netconnection = client->netconnection; + + if (svFPM.loadgame) + Q_memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms)); + Q_memset (client, 0, sizeof(*client)); + client->netconnection = netconnection; + + strcpy (client->name, "unconnected"); + client->active = true; + client->spawned = false; + client->edict = ent; + client->message.data = client->msgbuf; + client->message.maxsize = sizeof(client->msgbuf); + client->message.allowoverflow = true; // we can catch it + +#ifdef IDGODS + client->privileged = IsID(&client->netconnection->addr); +#else + client->privileged = false; +#endif + + if (svFPM.loadgame) + Q_memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms)); + else + { + // call the progs to get default spawn parms for the new client + PR_ExecuteProgramFPM (pr_global_struct->SetNewParms); + for (i=0 ; ispawn_parms[i] = (&pr_global_struct->parm1)[i]; + } + + SV_SendServerinfoFPM (client); +} +#endif //USEFPM + +/* +=================== +SV_CheckForNewClients + +=================== +*/ +void SV_CheckForNewClients (void) +{ + struct qsocket_s *ret; + int i; + +// +// check for new connections +// + + GpError("SV_CheckForNewClientrs",0); + while (1) + { + ret = NET_CheckNewConnections (); + if (!ret) + break; + + // + // init a new client structure + // + for (i=0 ; icontents < 0) + { + if (node->contents != CONTENTS_SOLID) + { + pvs = Mod_LeafPVS ( (mleaf_t *)node, sv.worldmodel); + for (i=0 ; iplane; + d = DotProduct (org, plane->normal) - plane->dist; + if (d > 8) + node = node->children[0]; + else if (d < -8) + node = node->children[1]; + else + { // go down both + SV_AddToFatPVS (org, node->children[0]); + node = node->children[1]; + } + } +} + +#ifdef USEFPM +void SV_AddToFatPVSFPM (vec3_FPM_t org, mnode_FPM_t *node) +{ + int i; + byte *pvs; + mplane_FPM_t *plane; + fixedpoint_t d; + + while (1) + { + // if this is a leaf, accumulate the pvs bits + if (node->contents < 0) + { + if (node->contents != CONTENTS_SOLID) + { + pvs = Mod_LeafPVSFPM ( (mleaf_FPM_t *)node, svFPM.worldmodel); + for (i=0 ; iplane; + d = FPM_SUB(DotProductFPM (org, plane->normal), plane->dist); + if (d > FPM_FROMLONGC(8)) + node = node->children[0]; + else if (d < FPM_FROMLONGC(-8)) + node = node->children[1]; + else + { // go down both + SV_AddToFatPVSFPM (org, node->children[0]); + node = node->children[1]; + } + } +} +#endif //USEFPM + +/* +============= +SV_FatPVS + +Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the +given point. +============= +*/ +byte *SV_FatPVS (vec3_t org) +{ + fatbytes = (sv.worldmodel->numleafs+31)>>3; + Q_memset (fatpvs, 0, fatbytes); + SV_AddToFatPVS (org, sv.worldmodel->nodes); + return fatpvs; +} + +#ifdef USEFPM +byte *SV_FatPVSFPM (vec3_FPM_t org) +{ + fatbytes = (svFPM.worldmodel->numleafs+31)>>3; + Q_memset (fatpvs, 0, fatbytes); + SV_AddToFatPVSFPM (org, svFPM.worldmodel->nodes); + return fatpvs; +} +#endif //USEFPM +//============================================================================= + + +/* +============= +SV_WriteEntitiesToClient + +============= +*/ +void SV_WriteEntitiesToClient (edict_t *clent, sizebuf_t *msg) +{ + int e, i; + int bits; + byte *pvs; + vec3_t org; + float miss; + edict_t *ent; + +// find the client's PVS + VectorAdd (clent->v.origin, clent->v.view_ofs, org); + pvs = SV_FatPVS (org); + +// send over all entities (excpet the client) that touch the pvs + ent = NEXT_EDICT(sv.edicts); + for (e=1 ; ev.effects == EF_NODRAW) + continue; +#endif + +// ignore if not touching a PV leaf + if (ent != clent) // clent is ALLWAYS sent + { +// ignore ents without visible models + if (!ent->v.modelindex || !pr_strings[ent->v.model]) + continue; + + for (i=0 ; i < ent->num_leafs ; i++) + if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) )) + break; + + if (i == ent->num_leafs) + continue; // not visible + } + + if (msg->maxsize - msg->cursize < 16) + { + Con_Printf ("packet overflow\n"); + return; + } + +// send an update + bits = 0; + + for (i=0 ; i<3 ; i++) + { + miss = ent->v.origin[i] - ent->baseline.origin[i]; + if ( miss < -0.1 || miss > 0.1 ) + bits |= U_ORIGIN1<v.angles[0] != ent->baseline.angles[0] ) + bits |= U_ANGLE1; + + if ( ent->v.angles[1] != ent->baseline.angles[1] ) + bits |= U_ANGLE2; + + if ( ent->v.angles[2] != ent->baseline.angles[2] ) + bits |= U_ANGLE3; + + if (ent->v.movetype == MOVETYPE_STEP) + bits |= U_NOLERP; // don't mess up the step animation + + if (ent->baseline.colormap != ent->v.colormap) + bits |= U_COLORMAP; + + if (ent->baseline.skin != ent->v.skin) + bits |= U_SKIN; + + if (ent->baseline.frame != ent->v.frame) + bits |= U_FRAME; + + if (ent->baseline.effects != ent->v.effects) + bits |= U_EFFECTS; + + if (ent->baseline.modelindex != ent->v.modelindex) + bits |= U_MODEL; + + if (e >= 256) + bits |= U_LONGENTITY; + + if (bits >= 256) + bits |= U_MOREBITS; + + // + // write the message + // + MSG_WriteByte (msg,bits | U_SIGNAL); + + if (bits & U_MOREBITS) + MSG_WriteByte (msg, bits>>8); + if (bits & U_LONGENTITY) + MSG_WriteShort (msg,e); + else + MSG_WriteByte (msg,e); + + if (bits & U_MODEL) + MSG_WriteByte (msg, (int)ent->v.modelindex); + if (bits & U_FRAME) + MSG_WriteByte (msg, (int)ent->v.frame); + if (bits & U_COLORMAP) + MSG_WriteByte (msg, (int)ent->v.colormap); + if (bits & U_SKIN) + MSG_WriteByte (msg, (int)ent->v.skin); + if (bits & U_EFFECTS) + MSG_WriteByte (msg, (int)ent->v.effects); + if (bits & U_ORIGIN1) + MSG_WriteCoord (msg, ent->v.origin[0]); + if (bits & U_ANGLE1) + MSG_WriteAngle(msg, ent->v.angles[0]); + if (bits & U_ORIGIN2) + MSG_WriteCoord (msg, ent->v.origin[1]); + if (bits & U_ANGLE2) + MSG_WriteAngle(msg, ent->v.angles[1]); + if (bits & U_ORIGIN3) + MSG_WriteCoord (msg, ent->v.origin[2]); + if (bits & U_ANGLE3) + MSG_WriteAngle(msg, ent->v.angles[2]); + } +} + +#ifdef USEFPM +void SV_WriteEntitiesToClientFPM (edict_FPM_t *clent, sizebuf_t *msg) +{ + int e, i; + int bits; + byte *pvs; + vec3_FPM_t org; + vec3_t tmp; + fixedpoint_t miss; + edict_FPM_t *ent; + +// find the client's PVS + VectorAdd (clent->v.origin, clent->v.view_ofs, tmp); + + org[0]=FPM_FROMFLOAT(tmp[0]); + org[1]=FPM_FROMFLOAT(tmp[1]); + org[2]=FPM_FROMFLOAT(tmp[2]); + pvs = SV_FatPVSFPM (org); + +// send over all entities (excpet the client) that touch the pvs + ent = NEXT_EDICTFPM(svFPM.edicts); + for (e=1 ; ev.effects == EF_NODRAW) + continue; +#endif + +// ignore if not touching a PV leaf + if (ent != clent) // clent is ALLWAYS sent + { +// ignore ents without visible models + if (!ent->v.modelindex || !pr_strings[ent->v.model]) + continue; + + for (i=0 ; i < ent->num_leafs ; i++) + if (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) )) + break; + + if (i == ent->num_leafs) + continue; // not visible + } + + if (msg->maxsize - msg->cursize < 16) + { + Con_Printf ("packet overflow\n"); + return; + } + +// send an update + bits = 0; + + for (i=0 ; i<3 ; i++) + { + miss = FPM_SUB(FPM_FROMFLOAT(ent->v.origin[i]), ent->baseline.origin[i]); + if ( miss < FPM_FROMFLOATC(-0.1) || miss > FPM_FROMFLOATC(0.1) ) + bits |= U_ORIGIN1<v.angles[0] != ent->baseline.angles[0] ) + bits |= U_ANGLE1; + + if ( ent->v.angles[1] != ent->baseline.angles[1] ) + bits |= U_ANGLE2; + + if ( ent->v.angles[2] != ent->baseline.angles[2] ) + bits |= U_ANGLE3; + + if (ent->v.movetype == MOVETYPE_STEP) + bits |= U_NOLERP; // don't mess up the step animation + + if (ent->baseline.colormap != ent->v.colormap) + bits |= U_COLORMAP; + + if (ent->baseline.skin != ent->v.skin) + bits |= U_SKIN; + + if (ent->baseline.frame != ent->v.frame) + bits |= U_FRAME; + + if (ent->baseline.effects != ent->v.effects) + bits |= U_EFFECTS; + + if (ent->baseline.modelindex != ent->v.modelindex) + bits |= U_MODEL; + + if (e >= 256) + bits |= U_LONGENTITY; + + if (bits >= 256) + bits |= U_MOREBITS; + + // + // write the message + // + MSG_WriteByte (msg,bits | U_SIGNAL); + + if (bits & U_MOREBITS) + MSG_WriteByte (msg, bits>>8); + if (bits & U_LONGENTITY) + MSG_WriteShort (msg,e); + else + MSG_WriteByte (msg,e); + + if (bits & U_MODEL) + MSG_WriteByte (msg, (int)ent->v.modelindex); + if (bits & U_FRAME) + MSG_WriteByte (msg, (int)ent->v.frame); + if (bits & U_COLORMAP) + MSG_WriteByte (msg, (int)ent->v.colormap); + if (bits & U_SKIN) + MSG_WriteByte (msg, (int)ent->v.skin); + if (bits & U_EFFECTS) + MSG_WriteByte (msg, (int)ent->v.effects); + if (bits & U_ORIGIN1) + MSG_WriteCoord (msg, ent->v.origin[0]); + if (bits & U_ANGLE1) + MSG_WriteAngle(msg, ent->v.angles[0]); + if (bits & U_ORIGIN2) + MSG_WriteCoord (msg, ent->v.origin[1]); + if (bits & U_ANGLE2) + MSG_WriteAngle(msg, ent->v.angles[1]); + if (bits & U_ORIGIN3) + MSG_WriteCoord (msg, ent->v.origin[2]); + if (bits & U_ANGLE3) + MSG_WriteAngle(msg, ent->v.angles[2]); + } +} +#endif //USEFPM + +/* +============= +SV_CleanupEnts + +============= +*/ +void SV_CleanupEnts (void) +{ + int e; + edict_t *ent; + + ent = NEXT_EDICT(sv.edicts); + for (e=1 ; ev.effects = (float)((int)ent->v.effects & ~EF_MUZZLEFLASH); + } + +} + +#ifdef USEFPM +void SV_CleanupEntsFPM (void) +{ + int e; + edict_FPM_t *ent; + + ent = NEXT_EDICTFPM(svFPM.edicts); + for (e=1 ; ev.effects = (float)((int)ent->v.effects & ~EF_MUZZLEFLASH); + } + +} +#endif //USEFPM +/* +================== +SV_WriteClientdataToMessage + +================== +*/ +void SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg) +{ + int bits; + int i; + edict_t *other; + int items; +#ifndef QUAKE2 + eval_t *val; +#endif + + GpError("SV_WriteClientdataToMessage",0); + +// +// send a damage message +// + if (ent->v.dmg_take || ent->v.dmg_save) + { + other = PROG_TO_EDICT(ent->v.dmg_inflictor); + MSG_WriteByte (msg, svc_damage); + MSG_WriteByte (msg, (int)ent->v.dmg_save); + MSG_WriteByte (msg, (int)ent->v.dmg_take); + for (i=0 ; i<3 ; i++) + MSG_WriteCoord (msg, (float)(other->v.origin[i] + 0.5*(other->v.mins[i] + other->v.maxs[i]))); + + ent->v.dmg_take = 0; + ent->v.dmg_save = 0; + } + +// +// send the current viewpos offset from the view entity +// + SV_SetIdealPitch (); // how much to look up / down ideally + +// a fixangle might get lost in a dropped packet. Oh well. + if ( ent->v.fixangle ) + { + MSG_WriteByte (msg, svc_setangle); + for (i=0 ; i < 3 ; i++) + MSG_WriteAngle (msg, ent->v.angles[i] ); + ent->v.fixangle = 0; + } + + bits = 0; + + if (ent->v.view_ofs[2] != DEFAULT_VIEWHEIGHT) + bits |= SU_VIEWHEIGHT; + + if (ent->v.idealpitch) + bits |= SU_IDEALPITCH; + +// stuff the sigil bits into the high bits of items for sbar, or else +// mix in items2 +#ifdef QUAKE2 + items = (int)ent->v.items | ((int)ent->v.items2 << 23); +#else + val = GetEdictFieldValue(ent, "items2"); + + if (val) + items = (int)ent->v.items | ((int)val->_float << 23); + else + items = (int)ent->v.items | ((int)pr_global_struct->serverflags << 28); +#endif + + bits |= SU_ITEMS; + + if ( (int)ent->v.flags & FL_ONGROUND) + bits |= SU_ONGROUND; + + if ( ent->v.waterlevel >= 2) + bits |= SU_INWATER; + + for (i=0 ; i<3 ; i++) + { + if (ent->v.punchangle[i]) + bits |= (SU_PUNCH1<v.velocity[i]) + bits |= (SU_VELOCITY1<v.weaponframe) + bits |= SU_WEAPONFRAME; + + if (ent->v.armorvalue) + bits |= SU_ARMOR; + +// if (ent->v.weapon) + bits |= SU_WEAPON; + +// send the data + + MSG_WriteByte (msg, svc_clientdata); + MSG_WriteShort (msg, bits); + + if (bits & SU_VIEWHEIGHT) + MSG_WriteChar (msg, (int)ent->v.view_ofs[2]); + + if (bits & SU_IDEALPITCH) + MSG_WriteChar (msg, (int)ent->v.idealpitch); + + for (i=0 ; i<3 ; i++) + { + if (bits & (SU_PUNCH1<v.punchangle[i]); + if (bits & (SU_VELOCITY1<v.velocity[i]/16)); + } + +// [always sent] if (bits & SU_ITEMS) + MSG_WriteLong (msg, items); + + if (bits & SU_WEAPONFRAME) + MSG_WriteByte (msg, (int)ent->v.weaponframe); + if (bits & SU_ARMOR) + MSG_WriteByte (msg, (int)ent->v.armorvalue); + if (bits & SU_WEAPON) + MSG_WriteByte (msg, SV_ModelIndex(pr_strings+ent->v.weaponmodel)); + + MSG_WriteShort (msg, (int)ent->v.health); + MSG_WriteByte (msg, (int)ent->v.currentammo); + MSG_WriteByte (msg, (int)ent->v.ammo_shells); + MSG_WriteByte (msg, (int)ent->v.ammo_nails); + MSG_WriteByte (msg, (int)ent->v.ammo_rockets); + MSG_WriteByte (msg, (int)ent->v.ammo_cells); + + if (standard_quake) + { + MSG_WriteByte (msg, (int)ent->v.weapon); + } + else + { + for(i=0;i<32;i++) + { + if ( ((int)ent->v.weapon) & (1<v.dmg_take || ent->v.dmg_save) + { + other = PROG_TO_EDICT(ent->v.dmg_inflictor); + MSG_WriteByte (msg, svc_damage); + MSG_WriteByte (msg, (int)ent->v.dmg_save); + MSG_WriteByte (msg, (int)ent->v.dmg_take); + for (i=0 ; i<3 ; i++) + MSG_WriteCoord (msg, (float)(other->v.origin[i] + 0.5*(other->v.mins[i] + other->v.maxs[i]))); + + ent->v.dmg_take = 0; + ent->v.dmg_save = 0; + } + +// +// send the current viewpos offset from the view entity +// + SV_SetIdealPitchFPM (); // how much to look up / down ideally + +// a fixangle might get lost in a dropped packet. Oh well. + if ( ent->v.fixangle ) + { + MSG_WriteByte (msg, svc_setangle); + for (i=0 ; i < 3 ; i++) + MSG_WriteAngle (msg, ent->v.angles[i] ); + ent->v.fixangle = 0; + } + + bits = 0; + + if (ent->v.view_ofs[2] != DEFAULT_VIEWHEIGHT) + bits |= SU_VIEWHEIGHT; + + if (ent->v.idealpitch) + bits |= SU_IDEALPITCH; + +// stuff the sigil bits into the high bits of items for sbar, or else +// mix in items2 +#ifdef QUAKE2 + items = (int)ent->v.items | ((int)ent->v.items2 << 23); +#else + val = GetEdictFieldValueFPM(ent, "items2"); + + if (val) + items = (int)ent->v.items | ((int)val->_float << 23); + else + items = (int)ent->v.items | ((int)pr_global_struct->serverflags << 28); +#endif + + bits |= SU_ITEMS; + + if ( (int)ent->v.flags & FL_ONGROUND) + bits |= SU_ONGROUND; + + if ( ent->v.waterlevel >= 2) + bits |= SU_INWATER; + + for (i=0 ; i<3 ; i++) + { + if (ent->v.punchangle[i]) + bits |= (SU_PUNCH1<v.velocity[i]) + bits |= (SU_VELOCITY1<v.weaponframe) + bits |= SU_WEAPONFRAME; + + if (ent->v.armorvalue) + bits |= SU_ARMOR; + +// if (ent->v.weapon) + bits |= SU_WEAPON; + +// send the data + + MSG_WriteByte (msg, svc_clientdata); + MSG_WriteShort (msg, bits); + + if (bits & SU_VIEWHEIGHT) + MSG_WriteChar (msg, (int)ent->v.view_ofs[2]); + + if (bits & SU_IDEALPITCH) + MSG_WriteChar (msg, (int)ent->v.idealpitch); + + for (i=0 ; i<3 ; i++) + { + if (bits & (SU_PUNCH1<v.punchangle[i]); + if (bits & (SU_VELOCITY1<v.velocity[i]/16)); + } + +// [always sent] if (bits & SU_ITEMS) + MSG_WriteLong (msg, items); + + if (bits & SU_WEAPONFRAME) + MSG_WriteByte (msg, (int)ent->v.weaponframe); + if (bits & SU_ARMOR) + MSG_WriteByte (msg, (int)ent->v.armorvalue); + if (bits & SU_WEAPON) + MSG_WriteByte (msg, SV_ModelIndexFPM(pr_strings+ent->v.weaponmodel)); + + MSG_WriteShort (msg, (int)ent->v.health); + MSG_WriteByte (msg, (int)ent->v.currentammo); + MSG_WriteByte (msg, (int)ent->v.ammo_shells); + MSG_WriteByte (msg, (int)ent->v.ammo_nails); + MSG_WriteByte (msg, (int)ent->v.ammo_rockets); + MSG_WriteByte (msg, (int)ent->v.ammo_cells); + + if (standard_quake) + { + MSG_WriteByte (msg, (int)ent->v.weapon); + } + else + { + for(i=0;i<32;i++) + { + if ( ((int)ent->v.weapon) & (1<edict, &msg); + + SV_WriteEntitiesToClient (client->edict, &msg); + +// copy the server datagram if there is space + if (msg.cursize + sv.datagram.cursize < msg.maxsize) + SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize); + +// send the datagram + if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1) + { + GpError("SV_SendClientDatagram, -1",2); + SV_DropClient (true);// if the message couldn't send, kick off + return false; + } + + return true; +} + +#ifdef USEFPM +qboolean SV_SendClientDatagramFPM (client_FPM_t *client) +{ + byte buf[MAX_DATAGRAM]; + sizebuf_t msg; + + msg.data = buf; + msg.maxsize = sizeof(buf); + msg.cursize = 0; + + MSG_WriteByte (&msg, svc_time); + MSG_WriteFloat (&msg, (float)svFPM.time); + +// add the client specific data to the datagram + SV_WriteClientdataToMessageFPM (client->edict, &msg); + + SV_WriteEntitiesToClientFPM (client->edict, &msg); + +// copy the server datagram if there is space + if (msg.cursize + svFPM.datagram.cursize < msg.maxsize) + SZ_Write (&msg, svFPM.datagram.data, svFPM.datagram.cursize); + +// send the datagram + if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1) + { + SV_DropClient (true);// if the message couldn't send, kick off + return false; + } + + return true; +} +#endif //USEFPM + +/* +======================= +SV_UpdateToReliableMessages +======================= +*/ +void SV_UpdateToReliableMessages (void) +{ + int i, j; + client_t *client; + +// check for changes to be sent over the reliable streams + for (i=0, host_client = svs.clients ; iold_frags != host_client->edict->v.frags) + { + for (j=0, client = svs.clients ; jactive) + continue; + MSG_WriteByte (&client->message, svc_updatefrags); + MSG_WriteByte (&client->message, i); + MSG_WriteShort (&client->message, (int)host_client->edict->v.frags); + } + + host_client->old_frags = (int)host_client->edict->v.frags; + } + } + + for (j=0, client = svs.clients ; jactive) + continue; + SZ_Write (&client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize); + } + + SZ_Clear (&sv.reliable_datagram); +} + +#ifdef USEFPM +void SV_UpdateToReliableMessagesFPM (void) +{ + int i, j; + client_FPM_t *client; + +// check for changes to be sent over the reliable streams + for (i=0, host_clientFPM = svsFPM.clients ; iold_frags != host_clientFPM->edict->v.frags) + { + for (j=0, client = svsFPM.clients ; jactive) + continue; + MSG_WriteByte (&client->message, svc_updatefrags); + MSG_WriteByte (&client->message, i); + MSG_WriteShort (&client->message, (int)host_clientFPM->edict->v.frags); + } + + host_clientFPM->old_frags = (int)host_clientFPM->edict->v.frags; + } + } + + for (j=0, client = svsFPM.clients ; jactive) + continue; + SZ_Write (&client->message, svFPM.reliable_datagram.data, svFPM.reliable_datagram.cursize); + } + + SZ_Clear (&svFPM.reliable_datagram); +} +#endif //USEFPM + +/* +======================= +SV_SendNop + +Send a nop message without trashing or sending the accumulated client +message buffer +======================= +*/ +void SV_SendNop (client_t *client) +{ + sizebuf_t msg; + byte buf[4]; + + msg.data = buf; + msg.maxsize = sizeof(buf); + msg.cursize = 0; + + MSG_WriteChar (&msg, svc_nop); + + if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1){ + GpError("SV_SendNOP fail",2); + SV_DropClient (true); // if the message couldn't send, kick off + } + client->last_message = realtime; +} + +#ifdef USEFPM +void SV_SendNopFPM (client_FPM_t *client) +{ + sizebuf_t msg; + byte buf[4]; + + msg.data = buf; + msg.maxsize = sizeof(buf); + msg.cursize = 0; + + MSG_WriteChar (&msg, svc_nop); + + if (NET_SendUnreliableMessage (client->netconnection, &msg) == -1) + SV_DropClient (true); // if the message couldn't send, kick off + client->last_message = realtime; +} +#endif //USEFPM + +/* +======================= +SV_SendClientMessages +======================= +*/ +void SV_SendClientMessages (void) +{ + int i; + +// update frags, names, etc + + GpError("SV_SendClientMessages",2); + + SV_UpdateToReliableMessages (); + +// build individual updates + for (i=0, host_client = svs.clients ; iactive){ + continue; + } + + if (host_client->spawned) + { + if (!SV_SendClientDatagram (host_client)){ + continue; + } + } else { + // the player isn't totally in the game yet + // send small keepalive messages if too much time has passed + // send a full message when the next signon stage has been requested + // some other message data (name changes, etc) may accumulate + // between signon stages + if (!host_client->sendsignon) + { + if (realtime - host_client->last_message > 5) + SV_SendNop (host_client); + continue; // don't send out non-signon messages + } + + } + + // check for an overflowed message. Should only happen + // on a very fucked up connection that backs up a lot, then + // changes level + if (host_client->message.overflowed) + { + GpError("SV_SCM - overflowed",2); + SV_DropClient (true); + host_client->message.overflowed = false; + continue; + } + + if (host_client->message.cursize || host_client->dropasap) + { + + if (!NET_CanSendMessage (host_client->netconnection)) + { + GpError("SV_SCM - can't send",2); +// I_Printf ("can't write\n"); + continue; + } + + if (host_client->dropasap){ + GpError("SV_SCM - drop asap",2); + SV_DropClient (false); // went to another level + } + else + { + if (NET_SendMessage (host_client->netconnection , &host_client->message) == -1){ + GpError("SV_SCM - drop",2); + SV_DropClient (true); // if the message couldn't send, kick off + } + SZ_Clear (&host_client->message); + host_client->last_message = realtime; + host_client->sendsignon = false; + } + } + } + + GpError("SV_SendClientMessages - done",0); + +// clear muzzle flashes + SV_CleanupEnts (); +} + +#ifdef USEFPM +void SV_SendClientMessagesFPM (void) +{ + int i; + +// update frags, names, etc + SV_UpdateToReliableMessagesFPM (); + +// build individual updates + for (i=0, host_clientFPM = svsFPM.clients ; iactive) + continue; + + if (host_clientFPM->spawned) + { + if (!SV_SendClientDatagramFPM (host_clientFPM)) + continue; + } + else + { + // the player isn't totally in the game yet + // send small keepalive messages if too much time has passed + // send a full message when the next signon stage has been requested + // some other message data (name changes, etc) may accumulate + // between signon stages + if (!host_clientFPM->sendsignon) + { + if (realtime - host_clientFPM->last_message > 5) + SV_SendNopFPM (host_clientFPM); + continue; // don't send out non-signon messages + } + } + + // check for an overflowed message. + if (host_clientFPM->message.overflowed) + { + SV_DropClient (true); + host_clientFPM->message.overflowed = false; + continue; + } + + if (host_clientFPM->message.cursize || host_clientFPM->dropasap) + { + if (!NET_CanSendMessage (host_clientFPM->netconnection)) + { +// I_Printf ("can't write\n"); + continue; + } + + if (host_clientFPM->dropasap) + SV_DropClient (false); // went to another level + else + { + if (NET_SendMessage (host_clientFPM->netconnection + , &host_clientFPM->message) == -1) + SV_DropClientFPM (true); // if the message couldn't send, kick off + SZ_Clear (&host_clientFPM->message); + host_clientFPM->last_message = realtime; + host_clientFPM->sendsignon = false; + } + } + } + + +// clear muzzle flashes + SV_CleanupEntsFPM (); +} +#endif //USEFPM + +/* +============================================================================== + +SERVER SPAWNING + +============================================================================== +*/ + +/* +================ +SV_ModelIndex + +================ +*/ +int SV_ModelIndex (char *name) +{ + int i; + + if (!name || !name[0]) + return 0; + + for (i=0 ; ifree) + continue; + if (entnum > svs.maxclients && !svent->v.modelindex) + continue; + + // + // create entity baseline + // + VectorCopy (svent->v.origin, svent->baseline.origin); + VectorCopy (svent->v.angles, svent->baseline.angles); + svent->baseline.frame = (int)svent->v.frame; + svent->baseline.skin = (int)svent->v.skin; + if (entnum > 0 && entnum <= svs.maxclients) + { + svent->baseline.colormap = entnum; + svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl"); + } + else + { + svent->baseline.colormap = 0; + svent->baseline.modelindex = + SV_ModelIndex(pr_strings + svent->v.model); + } + + // + // add to the message + // + MSG_WriteByte (&sv.signon,svc_spawnbaseline); + MSG_WriteShort (&sv.signon,entnum); + + MSG_WriteByte (&sv.signon, svent->baseline.modelindex); + MSG_WriteByte (&sv.signon, svent->baseline.frame); + MSG_WriteByte (&sv.signon, svent->baseline.colormap); + MSG_WriteByte (&sv.signon, svent->baseline.skin); + for (i=0 ; i<3 ; i++) + { + MSG_WriteCoord(&sv.signon, svent->baseline.origin[i]); + MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]); + } + } + GpError("SV_CreateBaseLine Done",0); +} + +#ifdef USEFPM +void SV_CreateBaselineFPM (void) +{ + int i; + edict_FPM_t *svent; + int entnum; + + for (entnum = 0; entnum < svFPM.num_edicts ; entnum++) + { + // get the current server version + svent = EDICT_NUMFPM(entnum); + if (svent->free) + continue; + if (entnum > svsFPM.maxclients && !svent->v.modelindex) + continue; + + // + // create entity baseline + // + svent->baseline.origin[0]=FPM_FROMFLOAT(svent->v.origin[0]); + svent->baseline.origin[1]=FPM_FROMFLOAT(svent->v.origin[1]); + svent->baseline.origin[2]=FPM_FROMFLOAT(svent->v.origin[2]); + svent->baseline.angles[0]=FPM_FROMFLOAT(svent->v.angles[0]); + svent->baseline.angles[1]=FPM_FROMFLOAT(svent->v.angles[1]); + svent->baseline.angles[2]=FPM_FROMFLOAT(svent->v.angles[2]); + //VectorCopy (svent->v.origin, svent->baseline.origin); + //VectorCopy (svent->v.angles, svent->baseline.angles); + svent->baseline.frame = (int)svent->v.frame; + svent->baseline.skin = (int)svent->v.skin; + if (entnum > 0 && entnum <= svsFPM.maxclients) + { + svent->baseline.colormap = entnum; + svent->baseline.modelindex = SV_ModelIndexFPM("progs/player.mdl"); + } + else + { + svent->baseline.colormap = 0; + svent->baseline.modelindex = + SV_ModelIndexFPM(pr_strings + svent->v.model); + } + + // + // add to the message + // + MSG_WriteByte (&svFPM.signon,svc_spawnbaseline); + MSG_WriteShort (&svFPM.signon,entnum); + + MSG_WriteByte (&svFPM.signon, svent->baseline.modelindex); + MSG_WriteByte (&svFPM.signon, svent->baseline.frame); + MSG_WriteByte (&svFPM.signon, svent->baseline.colormap); + MSG_WriteByte (&svFPM.signon, svent->baseline.skin); + for (i=0 ; i<3 ; i++) + { + MSG_WriteCoord(&svFPM.signon, svent->v.origin[i]); + MSG_WriteAngle(&svFPM.signon, svent->v.angles[i]); + //MSG_WriteCoordFPM(&sv.signon, svent->baseline.origin[i]); + //MSG_WriteAngleFPM(&sv.signon, svent->baseline.angles[i]); + } + } +} +#endif //USEFPM + +/* +================ +SV_SendReconnect + +Tell all the clients that the server is changing levels +================ +*/ +void SV_SendReconnect (void) +{ + char data[128]; + sizebuf_t msg; + + GpError("Sv_SendReconnect",0); + + msg.data = data; + msg.cursize = 0; + msg.maxsize = sizeof(data); + + MSG_WriteChar (&msg, svc_stufftext); + MSG_WriteString (&msg, "reconnect\n"); + NET_SendToAll (&msg, 5); + + if (cls.state != ca_dedicated) +#ifdef QUAKE2 + Cbuf_InsertText ("reconnect\n"); +#else + Cmd_ExecuteString ("reconnect\n", src_command); +#endif +} + +/* +================ +SV_SaveSpawnparms + +Grabs the current state of each client for saving across the +transition to another level +================ +*/ +void SV_SaveSpawnparms (void) +{ + int i, j; + + svs.serverflags = (int)pr_global_struct->serverflags; + + for (i=0, host_client = svs.clients ; iactive) + continue; + + // call the progs to get default spawn parms for the new client + pr_global_struct->self = EDICT_TO_PROG(host_client->edict); + PR_ExecuteProgram (pr_global_struct->SetChangeParms); + for (j=0 ; jspawn_parms[j] = (&pr_global_struct->parm1)[j]; + } +} + +#ifdef USEFPM +void SV_SaveSpawnparmsFPM (void) +{ + int i, j; + + svsFPM.serverflags = (int)pr_global_struct->serverflags; + + for (i=0, host_clientFPM = svsFPM.clients ; iactive) + continue; + + // call the progs to get default spawn parms for the new client + pr_global_struct->self = EDICT_TO_PROGFPM(host_clientFPM->edict); + PR_ExecuteProgramFPM (pr_global_struct->SetChangeParms); + for (j=0 ; jspawn_parms[j] = (&pr_global_struct->parm1)[j]; + } +} +#endif //USEFPM + +/* +================ +SV_SpawnServer + +This is called at the start of each level +================ +*/ +extern float scr_centertime_off; + +#ifdef QUAKE2 +void SV_SpawnServer (char *server, char *startspot) +#else +void SV_SpawnServer (char *server) +#endif +{ + edict_t *ent; + int i; + + GpError("spawnserver", 0); + + // let's not have any servers with no name + if (hostname.string[0] == 0) + Cvar_Set ("hostname", "UNNAMED"); + scr_centertime_off = 0; + + Con_DPrintf ("SpawnServer: %s\n",server); + svs.changelevel_issued = false; // now safe to issue another + +// +// tell all connected clients that we are going to a new level +// + if (sv.active) + { + SV_SendReconnect (); + } + +// +// make cvars consistant +// + if (coop.value) + Cvar_SetValue ("deathmatch", 0); + current_skill = (int)(skill.value + 0.5); + if (current_skill < 0) + current_skill = 0; + if (current_skill > 3) + current_skill = 3; + + Cvar_SetValue ("skill", (float)current_skill); + +// +// set up the new server +// + Host_ClearMemory (); + + Q_memset (&sv, 0, sizeof(sv)); + + strcpy (sv.name, server); +#ifdef QUAKE2 + if (startspot) + strcpy(sv.startspot, startspot); +#endif + +// load progs to get entity field count + GpError("spawnserver - load progs", 0); + PR_LoadProgs (); + puts("progs loaded"); + +// allocate server memory + sv.max_edicts = MAX_EDICTS; + + sv.edicts = Hunk_AllocName (sv.max_edicts*pr_edict_size, "edicts"); + + sv.datagram.maxsize = sizeof(sv.datagram_buf); + sv.datagram.cursize = 0; + sv.datagram.data = sv.datagram_buf; + + sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf); + sv.reliable_datagram.cursize = 0; + sv.reliable_datagram.data = sv.reliable_datagram_buf; + + sv.signon.maxsize = sizeof(sv.signon_buf); + sv.signon.cursize = 0; + sv.signon.data = sv.signon_buf; + + puts("edict_num loop"); + +// leave slots at start for clients only + sv.num_edicts = svs.maxclients+1; + for (i=0 ; inumvertexes == -1) { + Con_Printf ("Couldn't spawn server %s\n", sv.modelname); + sv.active = false; + return; + } + sv.models[1] = sv.worldmodel; + puts("world model ok"); +// +// clear world interaction links +// + SV_ClearWorld (); + + puts("world cleared"); + + sv.sound_precache[0] = pr_strings; + + sv.model_precache[0] = pr_strings; + sv.model_precache[1] = sv.modelname; + for (i=1 ; inumsubmodels ; i++) { + sv.model_precache[1+i] = localmodels[i]; + sv.models[i+1] = Mod_ForName (localmodels[i], false); + } + +// +// load the rest of the entities +// + GpError("spawnserver - load entities", 0); + + ent = EDICT_NUM(0); + Q_memset (&ent->v, 0, progs->entityfields * 4); + ent->free = false; + ent->v.model = sv.worldmodel->name - pr_strings; + ent->v.modelindex = 1; // world model + ent->v.solid = SOLID_BSP; + ent->v.movetype = MOVETYPE_PUSH; + + if (coop.value) + pr_global_struct->coop = coop.value; + else + pr_global_struct->deathmatch = deathmatch.value; + + pr_global_struct->mapname = sv.name - pr_strings; +#ifdef QUAKE2 + pr_global_struct->startspot = sv.startspot - pr_strings; +#endif + +// serverflags are for cross level information (sigils) + pr_global_struct->serverflags = (float)svs.serverflags; + + ED_LoadFromFile (sv.worldmodel->entities); + + sv.active = true; + +// all setup is completed, any further precache statements are errors + sv.state = ss_active; + + GpError("spawnserver - precache complete", 0); + +// run two frames to allow everything to settle + host_frametime = 0.1; + SV_Physics (); + SV_Physics (); + +// create a baseline for more efficient communications + GpError("spawnserver - create baseline", 0); + SV_CreateBaseline (); + +// send serverinfo to all connected clients + GpError("spawnserver - send info", 0); + + for (i=0,host_client = svs.clients ; iactive) + SV_SendServerinfo (host_client); + + Con_DPrintf ("Server spawned.\n"); + GpError("spawnserver - done!", 0); +} + +#ifdef USEFPM +#ifdef QUAKE2 +void SV_SpawnServerFPM (char *server, char *startspot) +#else +void SV_SpawnServerFPM (char *server) +#endif +{ + edict_FPM_t *ent; + int i; + + GpError("spawnserverFPM",0); + // let's not have any servers with no name + if (hostname.string[0] == 0) + Cvar_Set ("hostname", "UNNAMED"); + scr_centertime_off = 0; + + Con_DPrintf ("SpawnServer: %s\n",server); + svsFPM.changelevel_issued = false; // now safe to issue another + +// +// tell all connected clients that we are going to a new level +// + if (svFPM.active) + { + SV_SendReconnect (); + } + +// +// make cvars consistant +// + if (coop.value) + Cvar_SetValue ("deathmatch", 0); + current_skill = (int)(skill.value + 0.5); + if (current_skill < 0) + current_skill = 0; + if (current_skill > 3) + current_skill = 3; + + Cvar_SetValue ("skill", (float)current_skill); + +// +// set up the new server +// + Host_ClearMemoryFPM (); + + Q_memset (&svFPM, 0, sizeof(svFPM)); + + strcpy (svFPM.name, server); +#ifdef QUAKE2 + if (startspot) + strcpy(svFPM.startspot, startspot); +#endif + +// load progs to get entity field count + GpError("spawnserver - load progs", 0); + PR_LoadProgs (); + GpError("spawnserver - load progs done", 0); + +// allocate server memory + svFPM.max_edicts = MAX_EDICTS; + + svFPM.edicts = Hunk_AllocName (svFPM.max_edicts*pr_edict_size, "edicts"); + GpError("hunk allocated"); + svFPM.datagram.maxsize = sizeof(svFPM.datagram_buf); + svFPM.datagram.cursize = 0; + svFPM.datagram.data = svFPM.datagram_buf; + + svFPM.reliable_datagram.maxsize = sizeof(svFPM.reliable_datagram_buf); + svFPM.reliable_datagram.cursize = 0; + svFPM.reliable_datagram.data = svFPM.reliable_datagram_buf; + + svFPM.signon.maxsize = sizeof(svFPM.signon_buf); + svFPM.signon.cursize = 0; + svFPM.signon.data = svFPM.signon_buf; + +// leave slots at start for clients only + svFPM.num_edicts = svsFPM.maxclients+1; + for (i=0 ; inumsubmodels ; i++) + { + svFPM.model_precache[1+i] = localmodels[i]; + svFPM.models[i+1] = Mod_ForNameFPM (localmodels[i], false); + } + +// +// load the rest of the entities +// + GpError("spawnserver - load entities", 0); + ent = EDICT_NUMFPM(0); + Q_memset (&ent->v, 0, progs->entityfields * 4); + ent->free = false; + ent->v.model = svFPM.worldmodel->name - pr_strings; + ent->v.modelindex = 1; // world model + ent->v.solid = SOLID_BSP; + ent->v.movetype = MOVETYPE_PUSH; + + if (coop.value) + pr_global_struct->coop = coop.value; + else + pr_global_struct->deathmatch = deathmatch.value; + + pr_global_struct->mapname = svFPM.name - pr_strings; +#ifdef QUAKE2 + pr_global_struct->startspot = svFPM.startspot - pr_strings; +#endif + +// serverflags are for cross level information (sigils) + pr_global_struct->serverflags = (float)svsFPM.serverflags; + + ED_LoadFromFileFPM (svFPM.worldmodel->entities); + + svFPM.active = true; + +// all setup is completed, any further precache statements are errors + svFPM.state = ss_active; + + GpError("spawnserver - precache complete", 0); + +// run two frames to allow everything to settle + host_frametime = 0.1; + SV_PhysicsFPM (); + SV_PhysicsFPM (); + +// create a baseline for more efficient communications + GpError("spawnserver - create baseline", 0); + SV_CreateBaselineFPM (); + +// send serverinfo to all connected clients + for (i=0,host_clientFPM = svsFPM.clients ; iactive) + SV_SendServerinfoFPM (host_clientFPM); + + Con_DPrintf ("Server spawned.\n"); + GpError("spawnserverFPM - done!", 0); +} +#endif //USEFPM diff --git a/project/jni/application/quake/source/sv_move.c b/project/jni/application/quake/source/sv_move.c new file mode 100644 index 000000000..12f82a319 --- /dev/null +++ b/project/jni/application/quake/source/sv_move.c @@ -0,0 +1,789 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sv_move.c -- monster movement + +#include "quakedef.h" + +#define STEPSIZE 18 + +/* +============= +SV_CheckBottom + +Returns false if any part of the bottom of the entity is off an edge that +is not a staircase. + +============= +*/ +int c_yes, c_no; + +qboolean SV_CheckBottom (edict_t *ent) +{ + vec3_t mins, maxs, start, stop; + trace_t trace; + int x, y; + float mid, bottom; + + VectorAdd (ent->v.origin, ent->v.mins, mins); + VectorAdd (ent->v.origin, ent->v.maxs, maxs); + +// if all of the points under the corners are solid world, don't bother +// with the tougher checks +// the corners must be within 16 of the midpoint + start[2] = mins[2] - 1; + for (x=0 ; x<=1 ; x++) + for (y=0 ; y<=1 ; y++) + { + start[0] = x ? maxs[0] : mins[0]; + start[1] = y ? maxs[1] : mins[1]; + if (SV_PointContents (start) != CONTENTS_SOLID) + goto realcheck; + } + + c_yes++; + return true; // we got out easy + +realcheck: + c_no++; +// +// check it for real... +// + start[2] = mins[2]; + +// the midpoint must be within 16 of the bottom + start[0] = stop[0] = (float)((mins[0] + maxs[0])*0.5); + start[1] = stop[1] = (float)((mins[1] + maxs[1])*0.5); + stop[2] = start[2] - 2*STEPSIZE; + trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent); + + if (trace.fraction == 1.0) + return false; + mid = bottom = trace.endpos[2]; + +// the corners must be within 16 of the midpoint + for (x=0 ; x<=1 ; x++) + for (y=0 ; y<=1 ; y++) + { + start[0] = stop[0] = x ? maxs[0] : mins[0]; + start[1] = stop[1] = y ? maxs[1] : mins[1]; + + trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent); + + if (trace.fraction != 1.0 && trace.endpos[2] > bottom) + bottom = trace.endpos[2]; + if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE) + return false; + } + + c_yes++; + return true; +} + +#ifdef USEFPM +qboolean SV_CheckBottomFPM (edict_FPM_t *ent) +{ + vec3_t tmpmins, tmpmaxs; + vec3_FPM_t start, stop, mins, maxs; + trace_FPM_t trace; + int x, y; + fixedpoint_t mid, bottom; + + VectorAdd (ent->v.origin, ent->v.mins, tmpmins); + VectorAdd (ent->v.origin, ent->v.maxs, tmpmaxs); + VectorToFPM(tmpmins, mins); + VectorToFPM(tmpmins, maxs); + +// if all of the points under the corners are solid world, don't bother +// with the tougher checks +// the corners must be within 16 of the midpoint + start[2] = FPM_SUB(mins[2], 1); + for (x=0 ; x<=1 ; x++) + for (y=0 ; y<=1 ; y++) + { + start[0] = x ? maxs[0] : mins[0]; + start[1] = y ? maxs[1] : mins[1]; + if (SV_PointContentsFPM (start) != CONTENTS_SOLID) + goto realcheck; + } + + c_yes++; + return true; // we got out easy + +realcheck: + c_no++; +// +// check it for real... +// + start[2] = mins[2]; + +// the midpoint must be within 16 of the bottom + start[0] = stop[0] = FPM_MUL(FPM_ADD(mins[0], maxs[0]), FPM_FROMFLOATC(0.5)); + start[1] = stop[1] = FPM_MUL(FPM_ADD(mins[1], maxs[1]), FPM_FROMFLOATC(0.5)); + stop[2] = FPM_SUB(start[2], FPM_FROMLONGC(2*STEPSIZE)); + trace = SV_MoveFPM (start, vec3_originFPM, vec3_originFPM, stop, true, ent); + + if (trace.fraction == FPM_FROMFLOATC(1.0)) + return false; + mid = bottom = trace.endpos[2]; + +// the corners must be within 16 of the midpoint + for (x=0 ; x<=1 ; x++) + for (y=0 ; y<=1 ; y++) + { + start[0] = stop[0] = x ? maxs[0] : mins[0]; + start[1] = stop[1] = y ? maxs[1] : mins[1]; + + trace = SV_MoveFPM (start, vec3_originFPM, vec3_originFPM, stop, true, ent); + + if (trace.fraction != FPM_FROMFLOATC(1.0) && trace.endpos[2] > bottom) + bottom = trace.endpos[2]; + if (trace.fraction == FPM_FROMFLOATC(1.0) || mid - trace.endpos[2] > STEPSIZE) + return false; + } + + c_yes++; + return true; +} +#endif //USEFPM + +/* +============= +SV_movestep + +Called by monster program code. +The move will be adjusted for slopes and stairs, but if the move isn't +possible, no move is done, false is returned, and +pr_global_struct->trace_normal is set to the normal of the blocking wall +============= +*/ +qboolean SV_movestep (edict_t *ent, vec3_t move, qboolean relink) +{ + float dz; + vec3_t oldorg, neworg, end; + trace_t trace; + int i; + edict_t *enemy; + +// try the move + VectorCopy (ent->v.origin, oldorg); + VectorAdd (ent->v.origin, move, neworg); + +// flying monsters don't step up + if ( (int)ent->v.flags & (FL_SWIM | FL_FLY) ) + { + // try one move with vertical motion, then one without + for (i=0 ; i<2 ; i++) + { + VectorAdd (ent->v.origin, move, neworg); + enemy = PROG_TO_EDICT(ent->v.enemy); + if (i == 0 && enemy != sv.edicts) + { + dz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2]; + if (dz > 40) + neworg[2] -= 8; + if (dz < 30) + neworg[2] += 8; + } + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, neworg, false, ent); + + if (trace.fraction == 1) + { + if ( ((int)ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY ) + return false; // swim monster left water + + VectorCopy (trace.endpos, ent->v.origin); + if (relink) + SV_LinkEdict (ent, true); + return true; + } + + if (enemy == sv.edicts) + break; + } + + return false; + } + +// push down from a step height above the wished position + neworg[2] += STEPSIZE; + VectorCopy (neworg, end); + end[2] -= STEPSIZE*2; + + trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent); + + if (trace.allsolid) + return false; + + if (trace.startsolid) + { + neworg[2] -= STEPSIZE; + trace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent); + if (trace.allsolid || trace.startsolid) + return false; + } + if (trace.fraction == 1) + { + // if monster had the ground pulled out, go ahead and fall + if ( (int)ent->v.flags & FL_PARTIALGROUND ) + { + VectorAdd (ent->v.origin, move, ent->v.origin); + if (relink) + SV_LinkEdict (ent, true); + ent->v.flags = (float)((int)ent->v.flags & ~FL_ONGROUND); +// Con_Printf ("fall down\n"); + return true; + } + + return false; // walked off an edge + } + +// check point traces down for dangling corners + VectorCopy (trace.endpos, ent->v.origin); + + if (!SV_CheckBottom (ent)) + { + if ( (int)ent->v.flags & FL_PARTIALGROUND ) + { // entity had floor mostly pulled out from underneath it + // and is trying to correct + if (relink) + SV_LinkEdict (ent, true); + return true; + } + VectorCopy (oldorg, ent->v.origin); + return false; + } + + if ( (int)ent->v.flags & FL_PARTIALGROUND ) + { +// Con_Printf ("back on ground\n"); + ent->v.flags = (float)((int)ent->v.flags & ~FL_PARTIALGROUND); + } + ent->v.groundentity = EDICT_TO_PROG(trace.ent); + +// the move is ok + if (relink) + SV_LinkEdict (ent, true); + return true; +} + +#ifdef USEFPM +qboolean SV_movestepFPM(edict_FPM_t *ent, vec3_FPM_t move, qboolean relink) +{ + fixedpoint_t dz; + vec3_FPM_t oldorg, neworg, end; + trace_FPM_t trace; + int i; + edict_FPM_t *enemy; + vec3_FPM_t vorigin, vmins, vmaxs; + vec3_t tmp; + + VectorToFPM(ent->v.origin, vorigin); + VectorToFPM(ent->v.mins, vmins); + VectorToFPM(ent->v.maxs, vmaxs); +// try the move + VectorCopy (vorigin, oldorg); + VectorAdd (vorigin, move, neworg); + +// flying monsters don't step up + if ( (int)ent->v.flags & (FL_SWIM | FL_FLY) ) + { + // try one move with vertical motion, then one without + for (i=0 ; i<2 ; i++) + { + VectorAdd (vorigin, move, neworg); + enemy = PROG_TO_EDICTFPM(ent->v.enemy); + if (i == 0 && enemy != svFPM.edicts) + { + dz = FPM_SUB(vorigin[2], FPM_FROMFLOAT(PROG_TO_EDICT(ent->v.enemy)->v.origin[2])); + if (dz > FPM_FROMLONGC(40)) + neworg[2] = FPM_SUB(neworg[2], FPM_FROMLONGC(8)); + if (dz < FPM_FROMLONGC(30)) + neworg[2] = FPM_ADD(neworg[2], FPM_FROMLONGC(8)); + } + trace = SV_MoveFPM (vorigin, vmins, vmaxs, neworg, false, ent); + + if (trace.fraction == FPM_FROMLONGC(1)) + { + if ( ((int)ent->v.flags & FL_SWIM) && SV_PointContentsFPM(trace.endpos) == CONTENTS_EMPTY ) + return false; // swim monster left water + FPMToVector(trace.endpos, ent->v.origin); + //VectorCopy (trace.endpos, ent->v.origin); + if (relink) + SV_LinkEdictFPM (ent, true); + return true; + } + + if (enemy == svFPM.edicts) + break; + } + + return false; + } + +// push down from a step height above the wished position + neworg[2] += STEPSIZE; + VectorCopy (neworg, end); + end[2] -= STEPSIZE*2; + + trace = SV_MoveFPM (neworg, vmins, vmaxs, end, false, ent); + + if (trace.allsolid) + return false; + + if (trace.startsolid) + { + neworg[2] -= STEPSIZE; + trace = SV_MoveFPM (neworg, vmins, vmaxs, end, false, ent); + if (trace.allsolid || trace.startsolid) + return false; + } + if (trace.fraction == 1) + { + // if monster had the ground pulled out, go ahead and fall + if ( (int)ent->v.flags & FL_PARTIALGROUND ) + { + FPMToVector(move, tmp); + VectorAdd (ent->v.origin, tmp, ent->v.origin); + if (relink) + SV_LinkEdictFPM (ent, true); + ent->v.flags = (float)((int)ent->v.flags & ~FL_ONGROUND); +// Con_Printf ("fall down\n"); + return true; + } + + return false; // walked off an edge + } + +// check point traces down for dangling corners + FPMToVector(trace.endpos, ent->v.origin); + //VectorCopy (trace.endpos, ent->v.origin); + + if (!SV_CheckBottomFPM (ent)) + { + if ( (int)ent->v.flags & FL_PARTIALGROUND ) + { // entity had floor mostly pulled out from underneath it + // and is trying to correct + if (relink) + SV_LinkEdictFPM (ent, true); + return true; + } + FPMToVector(oldorg, ent->v.origin); + //VectorCopy (oldorg, ent->v.origin); + return false; + } + + if ( (int)ent->v.flags & FL_PARTIALGROUND ) + { +// Con_Printf ("back on ground\n"); + ent->v.flags = (float)((int)ent->v.flags & ~FL_PARTIALGROUND); + } + ent->v.groundentity = EDICT_TO_PROGFPM(trace.ent); + +// the move is ok + if (relink) + SV_LinkEdictFPM (ent, true); + return true; +} +#endif //USEFPM +//============================================================================ + +/* +====================== +SV_StepDirection + +Turns to the movement direction, and walks the current distance if +facing it. + +====================== +*/ +void PF_changeyaw (void); +qboolean SV_StepDirection (edict_t *ent, float yaw, float dist) +{ + vec3_t move, oldorigin; + float delta; + + ent->v.ideal_yaw = yaw; + PF_changeyaw(); + + yaw = (float)(yaw*M_PI*2 / 360); + move[0] = (float)(cos(yaw)*dist); + move[1] = (float)(sin(yaw)*dist); + move[2] = 0; + + VectorCopy (ent->v.origin, oldorigin); + if (SV_movestep (ent, move, false)) + { + delta = ent->v.angles[YAW] - ent->v.ideal_yaw; + if (delta > 45 && delta < 315) + { // not turned far enough, so don't take the step + VectorCopy (oldorigin, ent->v.origin); + } + SV_LinkEdict (ent, true); + return true; + } + SV_LinkEdict (ent, true); + + return false; +} + +#ifdef USEFPM +void PF_changeyawFPM (void); +qboolean SV_StepDirectionFPM (edict_FPM_t *ent, fixedpoint_t yaw, fixedpoint_t dist) +{ + vec3_t oldorigin; + vec3_FPM_t move; + float delta; + + ent->v.ideal_yaw = FPM_TOFLOAT(yaw); + PF_changeyawFPM(); + + yaw = FPM_DIV(FPM_MUL(yaw,FPM_PI), FPM_FROMLONG(180)); + move[0] = FPM_MUL(FPM_COS(yaw),dist); + move[1] = FPM_MUL(FPM_SIN(yaw),dist); + move[2] = 0; + + VectorCopy (ent->v.origin, oldorigin); + if (SV_movestepFPM (ent, move, false)) + { + delta = ent->v.angles[YAW] - ent->v.ideal_yaw; + if (delta > 45 && delta < 315) + { // not turned far enough, so don't take the step + VectorCopy (oldorigin, ent->v.origin); + } + SV_LinkEdictFPM (ent, true); + return true; + } + SV_LinkEdictFPM (ent, true); + + return false; +} +#endif //USEFPM + +/* +====================== +SV_FixCheckBottom + +====================== +*/ +void SV_FixCheckBottom (edict_t *ent) +{ +// Con_Printf ("SV_FixCheckBottom\n"); + + ent->v.flags = (float)((int)ent->v.flags | FL_PARTIALGROUND); +} + +#ifdef USEFPM +void SV_FixCheckBottomFPM (edict_FPM_t *ent) +{ +// Con_Printf ("SV_FixCheckBottom\n"); + + ent->v.flags = (float)((int)ent->v.flags | FL_PARTIALGROUND); +} +#endif //USEFPM + +/* +================ +SV_NewChaseDir + +================ +*/ +#define DI_NODIR -1 +void SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist) +{ + float deltax,deltay; + float d[3]; + float tdir, olddir, turnaround; + + olddir = anglemod( (float)((int)(actor->v.ideal_yaw/45)*45) ); + turnaround = anglemod(olddir - 180); + + deltax = enemy->v.origin[0] - actor->v.origin[0]; + deltay = enemy->v.origin[1] - actor->v.origin[1]; + if (deltax>10) + d[1]= 0; + else if (deltax<-10) + d[1]= 180; + else + d[1]= DI_NODIR; + if (deltay<-10) + d[2]= 270; + else if (deltay>10) + d[2]= 90; + else + d[2]= DI_NODIR; + +// try direct route + if (d[1] != DI_NODIR && d[2] != DI_NODIR) + { + if (d[1] == 0) + tdir = (float)(d[2] == 90 ? 45 : 315); + else + tdir = (float)(d[2] == 90 ? 135 : 215); + + if (tdir != turnaround && SV_StepDirection(actor, tdir, dist)) + return; + } + +// try other directions + if ( ((rand()&3) & 1) || abs((int)deltay)>abs((int)deltax)) + { + tdir=d[1]; + d[1]=d[2]; + d[2]=tdir; + } + + if (d[1]!=DI_NODIR && d[1]!=turnaround + && SV_StepDirection(actor, d[1], dist)) + return; + + if (d[2]!=DI_NODIR && d[2]!=turnaround + && SV_StepDirection(actor, d[2], dist)) + return; + +/* there is no direct path to the player, so pick another direction */ + + if (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist)) + return; + + if (rand()&1) /*randomly determine direction of search*/ + { + for (tdir=0 ; tdir<=315 ; tdir += 45) + if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) + return; + } + else + { + for (tdir=315 ; tdir >=0 ; tdir -= 45) + if (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) ) + return; + } + + if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) ) + return; + + actor->v.ideal_yaw = olddir; // can't move + +// if a bridge was pulled out from underneath a monster, it may not have +// a valid standing position at all + + if (!SV_CheckBottom (actor)) + SV_FixCheckBottom (actor); + +} + +#ifdef USEFPM +void SV_NewChaseDirFPM (edict_FPM_t *actor, edict_FPM_t *enemy, fixedpoint_t dist) +{ + fixedpoint_t deltax,deltay; + fixedpoint_t d[3]; + fixedpoint_t tdir, olddir, turnaround; + + olddir = anglemodFPM(FPM_MUL(FPM_DIV(FPM_FROMFLOAT(actor->v.ideal_yaw),FPM_FROMLONGC(45)),FPM_FROMLONGC(45)) ); + turnaround = anglemodFPM(FPM_SUB(olddir, FPM_FROMLONGC(180))); + + deltax = FPM_SUB(FPM_FROMFLOAT(enemy->v.origin[0]), FPM_FROMFLOAT(actor->v.origin[0])); + deltay = FPM_SUB(FPM_FROMFLOAT(enemy->v.origin[1]), FPM_FROMFLOAT(actor->v.origin[1])); + if (deltax>FPM_FROMLONGC(10)) + d[1]= 0; + else if (deltaxFPM_FROMLONGC(10)) + d[2]= FPM_FROMLONGC(90); + else + d[2]= FPM_FROMLONGC(DI_NODIR); + +// try direct route + if (d[1] != FPM_FROMLONGC(DI_NODIR) && d[2] != FPM_FROMLONGC(DI_NODIR)) + { + if (d[1] == 0) + tdir = (d[2] == FPM_FROMLONGC(90) ? FPM_FROMLONGC(45) : FPM_FROMLONGC(315)); + else + tdir = (d[2] == FPM_FROMLONGC(90) ? FPM_FROMLONGC(135) : FPM_FROMLONGC(215)); + + if (tdir != turnaround && SV_StepDirectionFPM(actor, tdir, dist)) + return; + } + +// try other directions + if ( ((rand()&3) & 1) || abs((int)deltay)>abs((int)deltax)) + { + tdir=d[1]; + d[1]=d[2]; + d[2]=tdir; + } + + if (d[1]!=FPM_FROMLONGC(DI_NODIR) && d[1]!=turnaround + && SV_StepDirectionFPM(actor, d[1], dist)) + return; + + if (d[2]!=FPM_FROMLONGC(DI_NODIR) && d[2]!=turnaround + && SV_StepDirectionFPM(actor, d[2], dist)) + return; + +/* there is no direct path to the player, so pick another direction */ + + if (olddir!=FPM_FROMLONGC(DI_NODIR) && SV_StepDirectionFPM(actor, olddir, dist)) + return; + + if (rand()&1) /*randomly determine direction of search*/ + { + for (tdir=0 ; tdir<=FPM_FROMLONGC(315) ; tdir = FPM_ADD(tdir, FPM_FROMLONGC(45))) + if (tdir!=turnaround && SV_StepDirectionFPM(actor, tdir, dist) ) + return; + } + else + { + for (tdir=FPM_FROMLONGC(315) ; tdir >=0 ; tdir = FPM_SUB(tdir, FPM_FROMLONGC(45))) + if (tdir!=turnaround && SV_StepDirectionFPM(actor, tdir, dist) ) + return; + } + + if (turnaround != FPM_FROMLONGC(DI_NODIR) && SV_StepDirectionFPM(actor, turnaround, dist) ) + return; + + actor->v.ideal_yaw = FPM_TOFLOAT(olddir); // can't move + +// if a bridge was pulled out from underneath a monster, it may not have +// a valid standing position at all + + if (!SV_CheckBottomFPM (actor)) + SV_FixCheckBottomFPM (actor); + +} +#endif //USEFPM + +/* +====================== +SV_CloseEnough + +====================== +*/ +qboolean SV_CloseEnough (edict_t *ent, edict_t *goal, float dist) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if (goal->v.absmin[i] > ent->v.absmax[i] + dist) + return false; + if (goal->v.absmax[i] < ent->v.absmin[i] - dist) + return false; + } + return true; +} + +#ifdef USEFPM +qboolean SV_CloseEnoughFPM (edict_FPM_t *ent, edict_FPM_t *goal, fixedpoint_t dist) +{ + int i; + float distf=FPM_TOFLOAT(dist); + + for (i=0 ; i<3 ; i++) + { + if (goal->v.absmin[i] > ent->v.absmax[i] + distf) + return false; + if (goal->v.absmax[i] < ent->v.absmin[i] - distf) + return false; + } + return true; +} +#endif //USEFPM + +/* +====================== +SV_MoveToGoal + +====================== +*/ +void SV_MoveToGoal (void) +{ + edict_t *ent, *goal; + float dist; +#ifdef QUAKE2 + edict_t *enemy; +#endif + + ent = PROG_TO_EDICT(pr_global_struct->self); + goal = PROG_TO_EDICT(ent->v.goalentity); + dist = G_FLOAT(OFS_PARM0); + + if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) ) + { + G_FLOAT(OFS_RETURN) = 0; + return; + } + +// if the next step hits the enemy, return immediately +#ifdef QUAKE2 + enemy = PROG_TO_EDICT(ent->v.enemy); + if (enemy != sv.edicts && SV_CloseEnough (ent, enemy, dist) ) +#else + if ( PROG_TO_EDICT(ent->v.enemy) != sv.edicts && SV_CloseEnough (ent, goal, dist) ) +#endif + return; + +// bump around... + if ( (rand()&3)==1 || + !SV_StepDirection (ent, ent->v.ideal_yaw, dist)) + { + SV_NewChaseDir (ent, goal, dist); + } +} + +#ifdef USEFPM +void SV_MoveToGoalFPM (void) +{ + edict_FPM_t *ent, *goal; + fixedpoint_t dist; +#ifdef QUAKE2 + edict_FPM_t *enemy; +#endif + + ent = PROG_TO_EDICTFPM(pr_global_struct->self); + goal = PROG_TO_EDICTFPM(ent->v.goalentity); + dist = FPM_FROMFLOAT(G_FLOAT(OFS_PARM0)); + + if ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) ) + { + G_FLOAT(OFS_RETURN) = 0; + return; + } + +// if the next step hits the enemy, return immediately +#ifdef QUAKE2 + enemy = PROG_TO_EDICTFPM(ent->v.enemy); + if (enemy != svFPM.edicts && SV_CloseEnoughFPM (ent, enemy, dist) ) +#else + if ( PROG_TO_EDICTFPM(ent->v.enemy) != svFPM.edicts && SV_CloseEnoughFPM (ent, goal, dist) ) +#endif + return; + +// bump around... + if ( (rand()&3)==1 || + !SV_StepDirectionFPM (ent, FPM_FROMFLOAT(ent->v.ideal_yaw), dist)) + { + SV_NewChaseDirFPM (ent, goal, dist); + } +} +#endif //USEFPM \ No newline at end of file diff --git a/project/jni/application/quake/source/sv_phys.c b/project/jni/application/quake/source/sv_phys.c new file mode 100644 index 000000000..954bc7b02 --- /dev/null +++ b/project/jni/application/quake/source/sv_phys.c @@ -0,0 +1,1680 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sv_phys.c + +#include "quakedef.h" + +/* + + +pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move. + +onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects + +doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH +bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS +corpses are SOLID_NOT and MOVETYPE_TOSS +crates are SOLID_BBOX and MOVETYPE_TOSS +walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP +flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY + +solid_edge items only clip against bsp models. + +*/ + +cvar_t sv_friction = {"sv_friction","4",false,true}; +cvar_t sv_stopspeed = {"sv_stopspeed","100"}; +cvar_t sv_gravity = {"sv_gravity","800",false,true}; +cvar_t sv_maxvelocity = {"sv_maxvelocity","2000"}; +cvar_t sv_nostep = {"sv_nostep","0"}; + +#ifdef QUAKE2 +static vec3_t vec_origin = {0.0, 0.0, 0.0}; +#endif + +#define MOVE_EPSILON 0.01 + +void SV_Physics_Toss (edict_t *ent); + +/* +================ +SV_CheckAllEnts +================ +*/ +void SV_CheckAllEnts (void) +{ + int e; + edict_t *check; + +// see if any solid entities are inside the final position + check = NEXT_EDICT(sv.edicts); + for (e=1 ; efree) + continue; + if (check->v.movetype == MOVETYPE_PUSH + || check->v.movetype == MOVETYPE_NONE +#ifdef QUAKE2 + || check->v.movetype == MOVETYPE_FOLLOW +#endif + || check->v.movetype == MOVETYPE_NOCLIP) + continue; + + if (SV_TestEntityPosition (check)) + Con_Printf ("entity in invalid position\n"); + } +} + +/* +================ +SV_CheckVelocity +================ +*/ +void SV_CheckVelocity (edict_t *ent) +{ + int i; + +// +// bound velocity +// + for (i=0 ; i<3 ; i++) + { + if (IS_NAN(ent->v.velocity[i])) + { + Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->v.classname); + ent->v.velocity[i] = 0; + } + if (IS_NAN(ent->v.origin[i])) + { + Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->v.classname); + ent->v.origin[i] = 0; + } + if (ent->v.velocity[i] > sv_maxvelocity.value) + ent->v.velocity[i] = sv_maxvelocity.value; + else if (ent->v.velocity[i] < -sv_maxvelocity.value) + ent->v.velocity[i] = -sv_maxvelocity.value; + } +} + +/* +============= +SV_RunThink + +Runs thinking code if time. There is some play in the exact time the think +function will be called, because it is called before any movement is done +in a frame. Not used for pushmove objects, because they must be exact. +Returns false if the entity removed itself. +============= +*/ +qboolean SV_RunThink (edict_t *ent) +{ + float thinktime; + + thinktime = ent->v.nextthink; + if (thinktime <= 0 || thinktime > sv.time + host_frametime) + return true; + + if (thinktime < sv.time) + thinktime = (float)sv.time; // don't let things stay in the past. + // it is possible to start that way + // by a trigger with a local time. + ent->v.nextthink = 0; + pr_global_struct->time = thinktime; + pr_global_struct->self = EDICT_TO_PROG(ent); + pr_global_struct->other = EDICT_TO_PROG(sv.edicts); + PR_ExecuteProgram (ent->v.think); + return !ent->free; +} + +/* +================== +SV_Impact + +Two entities have touched, so run their touch functions +================== +*/ +void SV_Impact (edict_t *e1, edict_t *e2) +{ + int old_self, old_other; + + old_self = pr_global_struct->self; + old_other = pr_global_struct->other; + + pr_global_struct->time = (float)sv.time; + if (e1->v.touch && e1->v.solid != SOLID_NOT) + { + pr_global_struct->self = EDICT_TO_PROG(e1); + pr_global_struct->other = EDICT_TO_PROG(e2); + PR_ExecuteProgram (e1->v.touch); + } + + if (e2->v.touch && e2->v.solid != SOLID_NOT) + { + pr_global_struct->self = EDICT_TO_PROG(e2); + pr_global_struct->other = EDICT_TO_PROG(e1); + PR_ExecuteProgram (e2->v.touch); + } + + pr_global_struct->self = old_self; + pr_global_struct->other = old_other; +} + + +/* +================== +ClipVelocity + +Slide off of the impacting object +returns the blocked flags (1 = floor, 2 = step / wall) +================== +*/ +#define STOP_EPSILON 0.1 + +int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) +{ + float backoff; + float change; + int i, blocked; + + blocked = 0; + if (normal[2] > 0) + blocked |= 1; // floor + if (!normal[2]) + blocked |= 2; // step + + backoff = DotProduct (in, normal) * overbounce; + + for (i=0 ; i<3 ; i++) + { + change = normal[i]*backoff; + out[i] = in[i] - change; + if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) + out[i] = 0; + } + + return blocked; +} + + +/* +============ +SV_FlyMove + +The basic solid body movement clip that slides along multiple planes +Returns the clipflags if the velocity was modified (hit something solid) +1 = floor +2 = wall / step +4 = dead stop +If steptrace is not NULL, the trace of any vertical wall hit will be stored +============ +*/ +#define MAX_CLIP_PLANES 5 +int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace) +{ + int bumpcount, numbumps; + vec3_t dir; + float d; + int numplanes; + vec3_t planes[MAX_CLIP_PLANES]; + vec3_t primal_velocity, original_velocity, new_velocity; + int i, j; + trace_t trace; + vec3_t end; + float time_left; + int blocked; + + numbumps = 4; + + blocked = 0; + VectorCopy (ent->v.velocity, original_velocity); + VectorCopy (ent->v.velocity, primal_velocity); + numplanes = 0; + + time_left = time; + + for (bumpcount=0 ; bumpcountv.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2]) + break; + + for (i=0 ; i<3 ; i++) + end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i]; + + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent); + + if (trace.allsolid) + { // entity is trapped in another solid + VectorCopy (vec3_origin, ent->v.velocity); + return 3; + } + + if (trace.fraction > 0) + { // actually covered some distance + VectorCopy (trace.endpos, ent->v.origin); + VectorCopy (ent->v.velocity, original_velocity); + numplanes = 0; + } + + if (trace.fraction == 1) + break; // moved the entire distance + + if (!trace.ent) + Sys_Error ("SV_FlyMove: !trace.ent"); + + if (trace.plane.normal[2] > 0.7) + { + blocked |= 1; // floor + if (trace.ent->v.solid == SOLID_BSP) + { + ent->v.flags = (float)((int)ent->v.flags | FL_ONGROUND); + ent->v.groundentity = EDICT_TO_PROG(trace.ent); + } + } + if (!trace.plane.normal[2]) + { + blocked |= 2; // step + if (steptrace) + *steptrace = trace; // save for player extrafriction + } + +// +// run the impact function +// + SV_Impact (ent, trace.ent); + if (ent->free) + break; // removed by the impact function + + + time_left -= time_left * trace.fraction; + + // cliped to another plane + if (numplanes >= MAX_CLIP_PLANES) + { // this shouldn't really happen + VectorCopy (vec3_origin, ent->v.velocity); + return 3; + } + + VectorCopy (trace.plane.normal, planes[numplanes]); + numplanes++; + +// +// modify original_velocity so it parallels all of the clip planes +// + for (i=0 ; iv.velocity); + } + else + { // go along the crease + if (numplanes != 2) + { +// Con_Printf ("clip velocity, numplanes == %i\n",numplanes); + VectorCopy (vec3_origin, ent->v.velocity); + return 7; + } + CrossProduct (planes[0], planes[1], dir); + d = DotProduct (dir, ent->v.velocity); + VectorScale (dir, d, ent->v.velocity); + } + +// +// if original velocity is against the original velocity, stop dead +// to avoid tiny occilations in sloping corners +// + if (DotProduct (ent->v.velocity, primal_velocity) <= 0) + { + VectorCopy (vec3_origin, ent->v.velocity); + return blocked; + } + } + + return blocked; +} + + +/* +============ +SV_AddGravity + +============ +*/ +void SV_AddGravity (edict_t *ent) +{ + float ent_gravity; + +#ifdef QUAKE2 + if (ent->v.gravity) + ent_gravity = ent->v.gravity; + else + ent_gravity = 1.0; +#else + eval_t *val; + + val = GetEdictFieldValue(ent, "gravity"); + if (val && val->_float) + ent_gravity = val->_float; + else + ent_gravity = 1.0; +#endif + ent->v.velocity[2] -= (float)(ent_gravity * sv_gravity.value * host_frametime); +} + + +/* +=============================================================================== + +PUSHMOVE + +=============================================================================== +*/ + +/* +============ +SV_PushEntity + +Does not change the entities velocity at all +============ +*/ +trace_t SV_PushEntity (edict_t *ent, vec3_t push) +{ + trace_t trace; + vec3_t end; + + VectorAdd (ent->v.origin, push, end); + + if (ent->v.movetype == MOVETYPE_FLYMISSILE) + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent); + else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT) + // only clip against bmodels + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent); + else + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent); + + VectorCopy (trace.endpos, ent->v.origin); + SV_LinkEdict (ent, true); + + if (trace.ent) + SV_Impact (ent, trace.ent); + + return trace; +} + + +/* +============ +SV_PushMove + +============ +*/ +void SV_PushMove (edict_t *pusher, float movetime) +{ + int i, e; + edict_t *check, *block; + vec3_t mins, maxs, move; + vec3_t entorig, pushorig; + int num_moved; + edict_t *moved_edict[MAX_EDICTS]; + vec3_t moved_from[MAX_EDICTS]; + + if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2]) + { + pusher->v.ltime += movetime; + return; + } + + for (i=0 ; i<3 ; i++) + { + move[i] = pusher->v.velocity[i] * movetime; + mins[i] = pusher->v.absmin[i] + move[i]; + maxs[i] = pusher->v.absmax[i] + move[i]; + } + + VectorCopy (pusher->v.origin, pushorig); + +// move the pusher to it's final position + + VectorAdd (pusher->v.origin, move, pusher->v.origin); + pusher->v.ltime += movetime; + SV_LinkEdict (pusher, false); + + +// see if any solid entities are inside the final position + num_moved = 0; + check = NEXT_EDICT(sv.edicts); + for (e=1 ; efree) + continue; + if (check->v.movetype == MOVETYPE_PUSH + || check->v.movetype == MOVETYPE_NONE +#ifdef QUAKE2 + || check->v.movetype == MOVETYPE_FOLLOW +#endif + || check->v.movetype == MOVETYPE_NOCLIP) + continue; + + // if the entity is standing on the pusher, it will definately be moved + if ( ! ( ((int)check->v.flags & FL_ONGROUND) + && PROG_TO_EDICT(check->v.groundentity) == pusher) ) + { + if ( check->v.absmin[0] >= maxs[0] + || check->v.absmin[1] >= maxs[1] + || check->v.absmin[2] >= maxs[2] + || check->v.absmax[0] <= mins[0] + || check->v.absmax[1] <= mins[1] + || check->v.absmax[2] <= mins[2] ) + continue; + + // see if the ent's bbox is inside the pusher's final position + if (!SV_TestEntityPosition (check)) + continue; + } + + // remove the onground flag for non-players + if (check->v.movetype != MOVETYPE_WALK) + check->v.flags = (float)((int)check->v.flags & ~FL_ONGROUND); + + VectorCopy (check->v.origin, entorig); + VectorCopy (check->v.origin, moved_from[num_moved]); + moved_edict[num_moved] = check; + num_moved++; + + // try moving the contacted entity + pusher->v.solid = SOLID_NOT; + SV_PushEntity (check, move); + pusher->v.solid = SOLID_BSP; + + // if it is still inside the pusher, block + block = SV_TestEntityPosition (check); + if (block) + { // fail the move + if (check->v.mins[0] == check->v.maxs[0]) + continue; + if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) + { // corpse + check->v.mins[0] = check->v.mins[1] = 0; + VectorCopy (check->v.mins, check->v.maxs); + continue; + } + + VectorCopy (entorig, check->v.origin); + SV_LinkEdict (check, true); + + VectorCopy (pushorig, pusher->v.origin); + SV_LinkEdict (pusher, false); + pusher->v.ltime -= movetime; + + // if the pusher has a "blocked" function, call it + // otherwise, just stay in place until the obstacle is gone + if (pusher->v.blocked) + { + pr_global_struct->self = EDICT_TO_PROG(pusher); + pr_global_struct->other = EDICT_TO_PROG(check); + PR_ExecuteProgram (pusher->v.blocked); + } + + // move back any entities we already moved + for (i=0 ; iv.origin); + SV_LinkEdict (moved_edict[i], false); + } + return; + } + } + + +} + +#ifdef QUAKE2 +/* +============ +SV_PushRotate + +============ +*/ +void SV_PushRotate (edict_t *pusher, float movetime) +{ + int i, e; + edict_t *check, *block; + vec3_t move, a, amove; + vec3_t entorig, pushorig; + int num_moved; + edict_t *moved_edict[MAX_EDICTS]; + vec3_t moved_from[MAX_EDICTS]; + vec3_t org, org2; + vec3_t forward, right, up; + + if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2]) + { + pusher->v.ltime += movetime; + return; + } + + for (i=0 ; i<3 ; i++) + amove[i] = pusher->v.avelocity[i] * movetime; + + VectorSubtract (vec3_origin, amove, a); + AngleVectors (a, forward, right, up); + + VectorCopy (pusher->v.angles, pushorig); + +// move the pusher to it's final position + + VectorAdd (pusher->v.angles, amove, pusher->v.angles); + pusher->v.ltime += movetime; + SV_LinkEdict (pusher, false); + + +// see if any solid entities are inside the final position + num_moved = 0; + check = NEXT_EDICT(sv.edicts); + for (e=1 ; efree) + continue; + if (check->v.movetype == MOVETYPE_PUSH + || check->v.movetype == MOVETYPE_NONE + || check->v.movetype == MOVETYPE_FOLLOW + || check->v.movetype == MOVETYPE_NOCLIP) + continue; + + // if the entity is standing on the pusher, it will definately be moved + if ( ! ( ((int)check->v.flags & FL_ONGROUND) + && PROG_TO_EDICT(check->v.groundentity) == pusher) ) + { + if ( check->v.absmin[0] >= pusher->v.absmax[0] + || check->v.absmin[1] >= pusher->v.absmax[1] + || check->v.absmin[2] >= pusher->v.absmax[2] + || check->v.absmax[0] <= pusher->v.absmin[0] + || check->v.absmax[1] <= pusher->v.absmin[1] + || check->v.absmax[2] <= pusher->v.absmin[2] ) + continue; + + // see if the ent's bbox is inside the pusher's final position + if (!SV_TestEntityPosition (check)) + continue; + } + + // remove the onground flag for non-players + if (check->v.movetype != MOVETYPE_WALK) + check->v.flags = (int)check->v.flags & ~FL_ONGROUND; + + VectorCopy (check->v.origin, entorig); + VectorCopy (check->v.origin, moved_from[num_moved]); + moved_edict[num_moved] = check; + num_moved++; + + // calculate destination position + VectorSubtract (check->v.origin, pusher->v.origin, org); + org2[0] = DotProduct (org, forward); + org2[1] = -DotProduct (org, right); + org2[2] = DotProduct (org, up); + VectorSubtract (org2, org, move); + + // try moving the contacted entity + pusher->v.solid = SOLID_NOT; + SV_PushEntity (check, move); + pusher->v.solid = SOLID_BSP; + + // if it is still inside the pusher, block + block = SV_TestEntityPosition (check); + if (block) + { // fail the move + if (check->v.mins[0] == check->v.maxs[0]) + continue; + if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER) + { // corpse + check->v.mins[0] = check->v.mins[1] = 0; + VectorCopy (check->v.mins, check->v.maxs); + continue; + } + + VectorCopy (entorig, check->v.origin); + SV_LinkEdict (check, true); + + VectorCopy (pushorig, pusher->v.angles); + SV_LinkEdict (pusher, false); + pusher->v.ltime -= movetime; + + // if the pusher has a "blocked" function, call it + // otherwise, just stay in place until the obstacle is gone + if (pusher->v.blocked) + { + pr_global_struct->self = EDICT_TO_PROG(pusher); + pr_global_struct->other = EDICT_TO_PROG(check); + PR_ExecuteProgram (pusher->v.blocked); + } + + // move back any entities we already moved + for (i=0 ; iv.origin); + VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles); + SV_LinkEdict (moved_edict[i], false); + } + return; + } + else + { + VectorAdd (check->v.angles, amove, check->v.angles); + } + } + + +} +#endif + +/* +================ +SV_Physics_Pusher + +================ +*/ +void SV_Physics_Pusher (edict_t *ent) +{ + float thinktime; + float oldltime; + float movetime; + + oldltime = ent->v.ltime; + + thinktime = ent->v.nextthink; + if (thinktime < ent->v.ltime + host_frametime) + { + movetime = thinktime - ent->v.ltime; + if (movetime < 0) + movetime = 0; + } + else + movetime = (float)host_frametime; + + if (movetime) + { +#ifdef QUAKE2 + if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2]) + SV_PushRotate (ent, movetime); + else +#endif + SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked + } + + if (thinktime > oldltime && thinktime <= ent->v.ltime) + { + ent->v.nextthink = 0; + pr_global_struct->time = (float)sv.time; + pr_global_struct->self = EDICT_TO_PROG(ent); + pr_global_struct->other = EDICT_TO_PROG(sv.edicts); + PR_ExecuteProgram (ent->v.think); + if (ent->free) + return; + } + +} + + +/* +=============================================================================== + +CLIENT MOVEMENT + +=============================================================================== +*/ + +/* +============= +SV_CheckStuck + +This is a big hack to try and fix the rare case of getting stuck in the world +clipping hull. +============= +*/ +void SV_CheckStuck (edict_t *ent) +{ + int i, j; + int z; + vec3_t org; + + if (!SV_TestEntityPosition(ent)) + { + VectorCopy (ent->v.origin, ent->v.oldorigin); + return; + } + + VectorCopy (ent->v.origin, org); + VectorCopy (ent->v.oldorigin, ent->v.origin); + if (!SV_TestEntityPosition(ent)) + { + Con_DPrintf ("Unstuck.\n"); + SV_LinkEdict (ent, true); + return; + } + + for (z=0 ; z< 18 ; z++) + for (i=-1 ; i <= 1 ; i++) + for (j=-1 ; j <= 1 ; j++) + { + ent->v.origin[0] = org[0] + i; + ent->v.origin[1] = org[1] + j; + ent->v.origin[2] = org[2] + z; + if (!SV_TestEntityPosition(ent)) + { + Con_DPrintf ("Unstuck.\n"); + SV_LinkEdict (ent, true); + return; + } + } + + VectorCopy (org, ent->v.origin); + Con_DPrintf ("player is stuck.\n"); +} + + +/* +============= +SV_CheckWater +============= +*/ +qboolean SV_CheckWater (edict_t *ent) +{ + vec3_t point; + int cont; +#ifdef QUAKE2 + int truecont; +#endif + + point[0] = ent->v.origin[0]; + point[1] = ent->v.origin[1]; + point[2] = ent->v.origin[2] + ent->v.mins[2] + 1; + + ent->v.waterlevel = 0; + ent->v.watertype = CONTENTS_EMPTY; + cont = SV_PointContents (point); + if (cont <= CONTENTS_WATER) + { +#ifdef QUAKE2 + truecont = SV_TruePointContents (point); +#endif + ent->v.watertype = (float)cont; + ent->v.waterlevel = 1; + point[2] = (float)(ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5); + cont = SV_PointContents (point); + if (cont <= CONTENTS_WATER) + { + ent->v.waterlevel = 2; + point[2] = ent->v.origin[2] + ent->v.view_ofs[2]; + cont = SV_PointContents (point); + if (cont <= CONTENTS_WATER) + ent->v.waterlevel = 3; + } +#ifdef QUAKE2 + if (truecont <= CONTENTS_CURRENT_0 && truecont >= CONTENTS_CURRENT_DOWN) + { + static vec3_t current_table[] = + { + {1, 0, 0}, + {0, 1, 0}, + {-1, 0, 0}, + {0, -1, 0}, + {0, 0, 1}, + {0, 0, -1} + }; + + VectorMA (ent->v.basevelocity, 150.0*ent->v.waterlevel/3.0, current_table[CONTENTS_CURRENT_0 - truecont], ent->v.basevelocity); + } +#endif + } + + return ent->v.waterlevel > 1; +} + +/* +============ +SV_WallFriction + +============ +*/ +void SV_WallFriction (edict_t *ent, trace_t *trace) +{ + vec3_t forward, right, up; + float d, i; + vec3_t into, side; + + AngleVectors (ent->v.v_angle, forward, right, up); + d = DotProduct (trace->plane.normal, forward); + + d += 0.5; + if (d >= 0) + return; + +// cut the tangential velocity + i = DotProduct (trace->plane.normal, ent->v.velocity); + VectorScale (trace->plane.normal, i, into); + VectorSubtract (ent->v.velocity, into, side); + + ent->v.velocity[0] = side[0] * (1 + d); + ent->v.velocity[1] = side[1] * (1 + d); +} + +/* +===================== +SV_TryUnstick + +Player has come to a dead stop, possibly due to the problem with limited +float precision at some angle joins in the BSP hull. + +Try fixing by pushing one pixel in each direction. + +This is a hack, but in the interest of good gameplay... +====================== +*/ +int SV_TryUnstick (edict_t *ent, vec3_t oldvel) +{ + int i; + vec3_t oldorg; + vec3_t dir; + int clip; + trace_t steptrace; + + VectorCopy (ent->v.origin, oldorg); + VectorCopy (vec3_origin, dir); + + for (i=0 ; i<8 ; i++) + { +// try pushing a little in an axial direction + switch (i) + { + case 0: dir[0] = 2; dir[1] = 0; break; + case 1: dir[0] = 0; dir[1] = 2; break; + case 2: dir[0] = -2; dir[1] = 0; break; + case 3: dir[0] = 0; dir[1] = -2; break; + case 4: dir[0] = 2; dir[1] = 2; break; + case 5: dir[0] = -2; dir[1] = 2; break; + case 6: dir[0] = 2; dir[1] = -2; break; + case 7: dir[0] = -2; dir[1] = -2; break; + } + + SV_PushEntity (ent, dir); + +// retry the original move + ent->v.velocity[0] = oldvel[0]; + ent->v. velocity[1] = oldvel[1]; + ent->v. velocity[2] = 0; + clip = SV_FlyMove (ent, (float)0.1, &steptrace); + + if ( fabs(oldorg[1] - ent->v.origin[1]) > 4 + || fabs(oldorg[0] - ent->v.origin[0]) > 4 ) + { +//Con_DPrintf ("unstuck!\n"); + return clip; + } + +// go back to the original pos and try again + VectorCopy (oldorg, ent->v.origin); + } + + VectorCopy (vec3_origin, ent->v.velocity); + return 7; // still not moving +} + +/* +===================== +SV_WalkMove + +Only used by players +====================== +*/ +#define STEPSIZE 18 +void SV_WalkMove (edict_t *ent) +{ + vec3_t upmove, downmove; + vec3_t oldorg, oldvel; + vec3_t nosteporg, nostepvel; + int clip; + int oldonground; + trace_t steptrace, downtrace; + +// +// do a regular slide move unless it looks like you ran into a step +// + oldonground = (int)ent->v.flags & FL_ONGROUND; + ent->v.flags = (float)((int)ent->v.flags & ~FL_ONGROUND); + + VectorCopy (ent->v.origin, oldorg); + VectorCopy (ent->v.velocity, oldvel); + + clip = SV_FlyMove (ent, (float)host_frametime, &steptrace); + + if ( !(clip & 2) ) + return; // move didn't block on a step + + if (!oldonground && ent->v.waterlevel == 0) + return; // don't stair up while jumping + + if (ent->v.movetype != MOVETYPE_WALK) + return; // gibbed by a trigger + + if (sv_nostep.value) + return; + + if ( (int)sv_player->v.flags & FL_WATERJUMP ) + return; + + VectorCopy (ent->v.origin, nosteporg); + VectorCopy (ent->v.velocity, nostepvel); + +// +// try moving up and forward to go up a step +// + VectorCopy (oldorg, ent->v.origin); // back to start pos + + VectorCopy (vec3_origin, upmove); + VectorCopy (vec3_origin, downmove); + upmove[2] = STEPSIZE; + downmove[2] = (float)(-STEPSIZE + oldvel[2]*host_frametime); + +// move up + SV_PushEntity (ent, upmove); // FIXME: don't link? + +// move forward + ent->v.velocity[0] = oldvel[0]; + ent->v. velocity[1] = oldvel[1]; + ent->v. velocity[2] = 0; + clip = SV_FlyMove (ent, (float)host_frametime, &steptrace); + +// check for stuckness, possibly due to the limited precision of floats +// in the clipping hulls + if (clip) + { + if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125 + && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 ) + { // stepping up didn't make any progress + clip = SV_TryUnstick (ent, oldvel); + } + } + +// extra friction based on view angle + if ( clip & 2 ) + SV_WallFriction (ent, &steptrace); + +// move down + downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link? + + if (downtrace.plane.normal[2] > 0.7) + { + if (ent->v.solid == SOLID_BSP) + { + ent->v.flags = (float)((int)ent->v.flags | FL_ONGROUND); + ent->v.groundentity = EDICT_TO_PROG(downtrace.ent); + } + } + else + { +// if the push down didn't end up on good ground, use the move without +// the step up. This happens near wall / slope combinations, and can +// cause the player to hop up higher on a slope too steep to climb + VectorCopy (nosteporg, ent->v.origin); + VectorCopy (nostepvel, ent->v.velocity); + } +} + + +/* +================ +SV_Physics_Client + +Player character actions +================ +*/ +void SV_Physics_Client (edict_t *ent, int num) +{ + if ( ! svs.clients[num-1].active ) + return; // unconnected slot + +// +// call standard client pre-think +// + pr_global_struct->time = (float)sv.time; + pr_global_struct->self = EDICT_TO_PROG(ent); + PR_ExecuteProgram (pr_global_struct->PlayerPreThink); + +// +// do a move +// + SV_CheckVelocity (ent); + +// +// decide which move function to call +// + switch ((int)ent->v.movetype) + { + case MOVETYPE_NONE: + if (!SV_RunThink (ent)) + return; + break; + + case MOVETYPE_WALK: + if (!SV_RunThink (ent)) + return; + if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) ) + SV_AddGravity (ent); + SV_CheckStuck (ent); +#ifdef QUAKE2 + VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); +#endif + SV_WalkMove (ent); + +#ifdef QUAKE2 + VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); +#endif + break; + + case MOVETYPE_TOSS: + case MOVETYPE_BOUNCE: + SV_Physics_Toss (ent); + break; + + case MOVETYPE_FLY: + if (!SV_RunThink (ent)) + return; + SV_FlyMove (ent, (float)host_frametime, NULL); + break; + + case MOVETYPE_NOCLIP: + if (!SV_RunThink (ent)) + return; + VectorMA (ent->v.origin, (float)host_frametime, ent->v.velocity, ent->v.origin); + break; + + default: + Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype); + } + +// +// call standard player post-think +// + SV_LinkEdict (ent, true); + + pr_global_struct->time = (float)sv.time; + pr_global_struct->self = EDICT_TO_PROG(ent); + PR_ExecuteProgram (pr_global_struct->PlayerPostThink); +} + +//============================================================================ + +/* +============= +SV_Physics_None + +Non moving objects can only think +============= +*/ +void SV_Physics_None (edict_t *ent) +{ +// regular thinking + SV_RunThink (ent); +} + +#ifdef QUAKE2 +/* +============= +SV_Physics_Follow + +Entities that are "stuck" to another entity +============= +*/ +void SV_Physics_Follow (edict_t *ent) +{ +// regular thinking + SV_RunThink (ent); + VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin); + SV_LinkEdict (ent, true); +} +#endif + +/* +============= +SV_Physics_Noclip + +A moving object that doesn't obey physics +============= +*/ +void SV_Physics_Noclip (edict_t *ent) +{ +// regular thinking + if (!SV_RunThink (ent)) + return; + + VectorMA (ent->v.angles, (float)host_frametime, ent->v.avelocity, ent->v.angles); + VectorMA (ent->v.origin, (float)host_frametime, ent->v.velocity, ent->v.origin); + + SV_LinkEdict (ent, false); +} + +/* +============================================================================== + +TOSS / BOUNCE + +============================================================================== +*/ + +/* +============= +SV_CheckWaterTransition + +============= +*/ +void SV_CheckWaterTransition (edict_t *ent) +{ + int cont; +#ifdef QUAKE2 + vec3_t point; + + point[0] = ent->v.origin[0]; + point[1] = ent->v.origin[1]; + point[2] = ent->v.origin[2] + ent->v.mins[2] + 1; + cont = SV_PointContents (point); +#else + cont = SV_PointContents (ent->v.origin); +#endif + if (!ent->v.watertype) + { // just spawned here + ent->v.watertype = (float)cont; + ent->v.waterlevel = 1; + return; + } + + if (cont <= CONTENTS_WATER) + { + if (ent->v.watertype == CONTENTS_EMPTY) + { // just crossed into water + SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); + } + ent->v.watertype = (float)cont; + ent->v.waterlevel = 1; + } + else + { + if (ent->v.watertype != CONTENTS_EMPTY) + { // just crossed into water + SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); + } + ent->v.watertype = CONTENTS_EMPTY; + ent->v.waterlevel = (float)cont; + } +} + +/* +============= +SV_Physics_Toss + +Toss, bounce, and fly movement. When onground, do nothing. +============= +*/ +void SV_Physics_Toss (edict_t *ent) +{ + trace_t trace; + vec3_t move; + float backoff; +#ifdef QUAKE2 + edict_t *groundentity; + + groundentity = PROG_TO_EDICT(ent->v.groundentity); + if ((int)groundentity->v.flags & FL_CONVEYOR) + VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity); + else + VectorCopy(vec_origin, ent->v.basevelocity); + SV_CheckWater (ent); +#endif + // regular thinking + if (!SV_RunThink (ent)) + return; + +#ifdef QUAKE2 + if (ent->v.velocity[2] > 0) + ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; + + if ( ((int)ent->v.flags & FL_ONGROUND) ) +//@@ + if (VectorCompare(ent->v.basevelocity, vec_origin)) + return; + + SV_CheckVelocity (ent); + +// add gravity + if (! ((int)ent->v.flags & FL_ONGROUND) + && ent->v.movetype != MOVETYPE_FLY + && ent->v.movetype != MOVETYPE_BOUNCEMISSILE + && ent->v.movetype != MOVETYPE_FLYMISSILE) + SV_AddGravity (ent); + +#else +// if onground, return without moving + if ( ((int)ent->v.flags & FL_ONGROUND) ) + return; + + SV_CheckVelocity (ent); + +// add gravity + if (ent->v.movetype != MOVETYPE_FLY + && ent->v.movetype != MOVETYPE_FLYMISSILE) + SV_AddGravity (ent); +#endif + +// move angles + VectorMA (ent->v.angles, (float)host_frametime, ent->v.avelocity, ent->v.angles); + +// move origin +#ifdef QUAKE2 + VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); +#endif + VectorScale (ent->v.velocity, (float)host_frametime, move); + trace = SV_PushEntity (ent, move); +#ifdef QUAKE2 + VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); +#endif + if (trace.fraction == 1) + return; + if (ent->free) + return; + + if (ent->v.movetype == MOVETYPE_BOUNCE) + backoff = 1.5; +#ifdef QUAKE2 + else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE) + backoff = 2.0; +#endif + else + backoff = 1; + + ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff); + +// stop if on ground + if (trace.plane.normal[2] > 0.7) + { +#ifdef QUAKE2 + if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE)) +#else + if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE) +#endif + { + ent->v.flags = (float)((int)ent->v.flags | FL_ONGROUND); + ent->v.groundentity = EDICT_TO_PROG(trace.ent); + VectorCopy (vec3_origin, ent->v.velocity); + VectorCopy (vec3_origin, ent->v.avelocity); + } + } + +// check for in water + SV_CheckWaterTransition (ent); +} + +/* +=============================================================================== + +STEPPING MOVEMENT + +=============================================================================== +*/ + +/* +============= +SV_Physics_Step + +Monsters freefall when they don't have a ground entity, otherwise +all movement is done with discrete steps. + +This is also used for objects that have become still on the ground, but +will fall if the floor is pulled out from under them. +============= +*/ +#ifdef QUAKE2 +void SV_Physics_Step (edict_t *ent) +{ + qboolean wasonground; + qboolean inwater; + qboolean hitsound = false; + float *vel; + float speed, newspeed, control; + float friction; + edict_t *groundentity; + + groundentity = PROG_TO_EDICT(ent->v.groundentity); + if ((int)groundentity->v.flags & FL_CONVEYOR) + VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity); + else + VectorCopy(vec_origin, ent->v.basevelocity); +//@@ + pr_global_struct->time = sv.time; + pr_global_struct->self = EDICT_TO_PROG(ent); + PF_WaterMove(); + + SV_CheckVelocity (ent); + + wasonground = (int)ent->v.flags & FL_ONGROUND; +// ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; + + // add gravity except: + // flying monsters + // swimming monsters who are in the water + inwater = SV_CheckWater(ent); + if (! wasonground) + if (!((int)ent->v.flags & FL_FLY)) + if (!(((int)ent->v.flags & FL_SWIM) && (ent->v.waterlevel > 0))) + { + if (ent->v.velocity[2] < sv_gravity.value*-0.1) + hitsound = true; + if (!inwater) + SV_AddGravity (ent); + } + + if (!VectorCompare(ent->v.velocity, vec_origin) || !VectorCompare(ent->v.basevelocity, vec_origin)) + { + ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND; + // apply friction + // let dead monsters who aren't completely onground slide + if (wasonground) + if (!(ent->v.health <= 0.0 && !SV_CheckBottom(ent))) + { + vel = ent->v.velocity; + speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); + if (speed) + { + friction = sv_friction.value; + + control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed; + newspeed = speed - host_frametime*control*friction; + + if (newspeed < 0) + newspeed = 0; + newspeed /= speed; + + vel[0] = vel[0] * newspeed; + vel[1] = vel[1] * newspeed; + } + } + + VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); + SV_FlyMove (ent, host_frametime, NULL); + VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity); + + // determine if it's on solid ground at all + { + vec3_t mins, maxs, point; + int x, y; + + VectorAdd (ent->v.origin, ent->v.mins, mins); + VectorAdd (ent->v.origin, ent->v.maxs, maxs); + + point[2] = mins[2] - 1; + for (x=0 ; x<=1 ; x++) + for (y=0 ; y<=1 ; y++) + { + point[0] = x ? maxs[0] : mins[0]; + point[1] = y ? maxs[1] : mins[1]; + if (SV_PointContents (point) == CONTENTS_SOLID) + { + ent->v.flags = (int)ent->v.flags | FL_ONGROUND; + break; + } + } + + } + + SV_LinkEdict (ent, true); + + if ((int)ent->v.flags & FL_ONGROUND) + if (!wasonground) + if (hitsound) + SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1); + } + +// regular thinking + SV_RunThink (ent); + SV_CheckWaterTransition (ent); +} +#else +void SV_Physics_Step (edict_t *ent) +{ + qboolean hitsound; + +// freefall if not onground + if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) ) + { + if (ent->v.velocity[2] < sv_gravity.value*-0.1) + hitsound = true; + else + hitsound = false; + + SV_AddGravity (ent); + SV_CheckVelocity (ent); + SV_FlyMove (ent, (float)host_frametime, NULL); + SV_LinkEdict (ent, true); + + if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground + { + if (hitsound) + SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1); + } + } + +// regular thinking + SV_RunThink (ent); + + SV_CheckWaterTransition (ent); +} +#endif + +//============================================================================ + +/* +================ +SV_Physics + +================ +*/ +void SV_Physics (void) +{ + int i; + edict_t *ent; + +// let the progs know that a new frame has started + pr_global_struct->self = EDICT_TO_PROG(sv.edicts); + pr_global_struct->other = EDICT_TO_PROG(sv.edicts); + pr_global_struct->time = (float)sv.time; + PR_ExecuteProgram (pr_global_struct->StartFrame); + +//SV_CheckAllEnts (); + +// +// treat each object in turn +// + ent = sv.edicts; + for (i=0 ; ifree) + continue; + + if (pr_global_struct->force_retouch) + { + SV_LinkEdict (ent, true); // force retouch even for stationary + } + + if (i > 0 && i <= svs.maxclients) + SV_Physics_Client (ent, i); + else if (ent->v.movetype == MOVETYPE_PUSH) + SV_Physics_Pusher (ent); + else if (ent->v.movetype == MOVETYPE_NONE) + SV_Physics_None (ent); +#ifdef QUAKE2 + else if (ent->v.movetype == MOVETYPE_FOLLOW) + SV_Physics_Follow (ent); +#endif + else if (ent->v.movetype == MOVETYPE_NOCLIP) + SV_Physics_Noclip (ent); + else if (ent->v.movetype == MOVETYPE_STEP) + SV_Physics_Step (ent); + else if (ent->v.movetype == MOVETYPE_TOSS + || ent->v.movetype == MOVETYPE_BOUNCE +#ifdef QUAKE2 + || ent->v.movetype == MOVETYPE_BOUNCEMISSILE +#endif + || ent->v.movetype == MOVETYPE_FLY + || ent->v.movetype == MOVETYPE_FLYMISSILE) + SV_Physics_Toss (ent); + else + Sys_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype); + } + + if (pr_global_struct->force_retouch) + pr_global_struct->force_retouch--; + + sv.time += host_frametime; +} + + +#ifdef USEFPM +void SV_PhysicsFPM (void) +{ + int i; + edict_FPM_t *ent; + +// let the progs know that a new frame has started + pr_global_struct->self = EDICT_TO_PROGFPM(svFPM.edicts); + pr_global_struct->other = EDICT_TO_PROGFPM(svFPM.edicts); + pr_global_struct->time = (float)svFPM.time; + PR_ExecuteProgramFPM (pr_global_struct->StartFrame); + +//SV_CheckAllEnts (); + +// +// treat each object in turn +// + ent = svFPM.edicts; + for (i=0 ; ifree) + continue; + + if (pr_global_struct->force_retouch) + { + SV_LinkEdictFPM (ent, true); // force retouch even for stationary + } + //Dan: TODO: +/* + if (i > 0 && i <= svsFPM.maxclients) + SV_Physics_Client (ent, i); + else if (ent->v.movetype == MOVETYPE_PUSH) + SV_Physics_Pusher (ent); + else if (ent->v.movetype == MOVETYPE_NONE) + SV_Physics_None (ent); +#ifdef QUAKE2 + else if (ent->v.movetype == MOVETYPE_FOLLOW) + SV_Physics_Follow (ent); +#endif + else if (ent->v.movetype == MOVETYPE_NOCLIP) + SV_Physics_Noclip (ent); + else if (ent->v.movetype == MOVETYPE_STEP) + SV_Physics_Step (ent); + else if (ent->v.movetype == MOVETYPE_TOSS + || ent->v.movetype == MOVETYPE_BOUNCE +#ifdef QUAKE2 + || ent->v.movetype == MOVETYPE_BOUNCEMISSILE +#endif + || ent->v.movetype == MOVETYPE_FLY + || ent->v.movetype == MOVETYPE_FLYMISSILE) + SV_Physics_Toss (ent); + else + Sys_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype); +*/ + } + + if (pr_global_struct->force_retouch) + pr_global_struct->force_retouch--; + + svFPM.time += host_frametime; +} +#endif //USEFPM + +#ifdef QUAKE2 +trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore) +{ + edict_t tempent, *tent; + trace_t trace; + vec3_t move; + vec3_t end; + double save_frametime; +// extern particle_t *active_particles, *free_particles; +// particle_t *p; + + + save_frametime = host_frametime; + host_frametime = 0.05; + + Q_memcpy(&tempent, ent, sizeof(edict_t)); + tent = &tempent; + + while (1) + { + SV_CheckVelocity (tent); + SV_AddGravity (tent); + VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles); + VectorScale (tent->v.velocity, host_frametime, move); + VectorAdd (tent->v.origin, move, end); + trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent); + VectorCopy (trace.endpos, tent->v.origin); + +// p = free_particles; +// if (p) +// { +// free_particles = p->next; +// p->next = active_particles; +// active_particles = p; +// +// p->die = 256; +// p->color = 15; +// p->type = pt_static; +// VectorCopy (vec3_origin, p->vel); +// VectorCopy (tent->v.origin, p->org); +// } + + if (trace.ent) + if (trace.ent != ignore) + break; + } +// p->color = 224; + host_frametime = save_frametime; + return trace; +} +#endif diff --git a/project/jni/application/quake/source/sv_user.c b/project/jni/application/quake/source/sv_user.c new file mode 100644 index 000000000..152f9aa3a --- /dev/null +++ b/project/jni/application/quake/source/sv_user.c @@ -0,0 +1,721 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sv_user.c -- server code for moving users + +#include "quakedef.h" + +edict_t *sv_player; + +#ifdef USEFPM +edict_FPM_t *sv_playerFPM; +#endif //USEFPM + +extern cvar_t sv_friction; +cvar_t sv_edgefriction = {"edgefriction", "2"}; +extern cvar_t sv_stopspeed; + +static vec3_t forward, right, up; + +vec3_t wishdir; +float wishspeed; + +// world +float *angles; +float *origin; +float *velocity; + +qboolean onground; + +usercmd_t cmd; + +cvar_t sv_idealpitchscale = {"sv_idealpitchscale","0.8"}; + + +/* +=============== +SV_SetIdealPitch +=============== +*/ +#define MAX_FORWARD 6 +void SV_SetIdealPitch (void) +{ + float angleval, sinval, cosval; + trace_t tr; + vec3_t top, bottom; + float z[MAX_FORWARD]; + int i, j; + int step, dir, steps; +// char buf[256]; + + if (!((int)sv_player->v.flags & FL_ONGROUND)) + return; + + angleval = (float)(sv_player->v.angles[YAW] * M_PI*2 / 360); + sinval = (float)sin(angleval); + cosval = (float)cos(angleval); + + //Dan: +// sprintf(buf, "%f %f ", sinval, cosval); +// LogIt(buf); + + for (i=0 ; iv.origin[0] + cosval*(i+3)*12; + top[1] = sv_player->v.origin[1] + sinval*(i+3)*12; + top[2] = sv_player->v.origin[2] + sv_player->v.view_ofs[2]; + + bottom[0] = top[0]; + bottom[1] = top[1]; + bottom[2] = top[2] - 160; + + tr = SV_Move (top, vec3_origin, vec3_origin, bottom, 1, sv_player); + if (tr.allsolid) + return; // looking at a wall, leave ideal the way is was + + if (tr.fraction == 1) + return; // near a dropoff + + z[i] = top[2] + tr.fraction*(bottom[2]-top[2]); + } + + dir = 0; + steps = 0; + for (j=1 ; j -ON_EPSILON && step < ON_EPSILON) + continue; + + if (dir && ( step-dir > ON_EPSILON || step-dir < -ON_EPSILON ) ) + return; // mixed changes + + steps++; + dir = step; + } + + if (!dir) + { + sv_player->v.idealpitch = 0; + return; + } + + if (steps < 2) + return; + sv_player->v.idealpitch = -dir * sv_idealpitchscale.value; +} + +#ifdef USEFPM +void SV_SetIdealPitchFPM (void) +{ + fixedpoint_t angleval, sinval, cosval; + trace_FPM_t tr; + vec3_FPM_t top, bottom; + fixedpoint_t z[MAX_FORWARD]; + int i, j; + int step, dir, steps; +// char buf[256]; + + if (!((int)sv_player->v.flags & FL_ONGROUND)) + return; + + angleval = FPM_FROMFLOAT(sv_player->v.angles[YAW]);// * M_PI*2 / 360; + sinval = FPM_SIN_DEG(angleval); + cosval = FPM_COS_DEG(angleval); + + //Dan: +// sprintf(buf, "%f %f ", sinval, cosval); +// LogIt(buf); + + for (i=0 ; iv.origin[0]), FPM_MUL(FPM_MUL(cosval,FPM_FROMLONG(i+3)),FPM_FROMLONGC(12))); + top[1] = FPM_DIV(FPM_FROMFLOAT(sv_player->v.origin[1]), FPM_MUL(FPM_MUL(sinval,FPM_FROMLONG(i+3)),FPM_FROMLONGC(12))); + top[2] = FPM_ADD(FPM_FROMFLOAT(sv_player->v.origin[2]), FPM_FROMFLOAT(sv_player->v.view_ofs[2])); + + bottom[0] = top[0]; + bottom[1] = top[1]; + bottom[2] = top[2] - 160; + + tr = SV_MoveFPM (top, vec3_originFPM, vec3_originFPM, bottom, 1, sv_playerFPM); + if (tr.allsolid) + return; // looking at a wall, leave ideal the way is was + + if (tr.fraction == 1) + return; // near a dropoff + + z[i] = FPM_ADD(top[2], FPM_MUL(FPM_FROMFLOAT(tr.fraction),FPM_SUB(bottom[2],top[2]))); + } + + dir = 0; + steps = 0; + for (j=1 ; j -ON_EPSILON && step < ON_EPSILON) + continue; + + if (dir && ( step-dir > ON_EPSILON || step-dir < -ON_EPSILON ) ) + return; // mixed changes + + steps++; + dir = step; + } + + if (!dir) + { + sv_player->v.idealpitch = 0; + return; + } + + if (steps < 2) + return; + sv_player->v.idealpitch = -dir * sv_idealpitchscale.value; +} +#endif //USEFPM + +/* +================== +SV_UserFriction + +================== +*/ +void SV_UserFriction (void) +{ + float *vel; + float speed, newspeed, control; + vec3_t start, stop; + float friction; + trace_t trace; + + vel = velocity; + + speed = (float)sqrt(vel[0]*vel[0] +vel[1]*vel[1]); + if (!speed) + return; + +// if the leading edge is over a dropoff, increase friction + start[0] = stop[0] = origin[0] + vel[0]/speed*16; + start[1] = stop[1] = origin[1] + vel[1]/speed*16; + start[2] = origin[2] + sv_player->v.mins[2]; + stop[2] = start[2] - 34; + + trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, sv_player); + + if (trace.fraction == 1.0) + friction = sv_friction.value*sv_edgefriction.value; + else + friction = sv_friction.value; + +// apply friction + control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed; + newspeed = (float)(speed - host_frametime*control*friction); + + if (newspeed < 0) + newspeed = 0; + newspeed /= speed; + + vel[0] = vel[0] * newspeed; + vel[1] = vel[1] * newspeed; + vel[2] = vel[2] * newspeed; +} + +/* +============== +SV_Accelerate +============== +*/ +cvar_t sv_maxspeed = {"sv_maxspeed", "320", false, true}; +cvar_t sv_accelerate = {"sv_accelerate", "10"}; +#if 0 +void SV_Accelerate (vec3_t wishvel) +{ + int i; + float addspeed, accelspeed; + vec3_t pushvec; + + if (wishspeed == 0) + return; + + VectorSubtract (wishvel, velocity, pushvec); + addspeed = VectorNormalize (pushvec); + + accelspeed = sv_accelerate.value*host_frametime*addspeed; + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + velocity[i] += accelspeed*pushvec[i]; +} +#endif +void SV_Accelerate (void) +{ + int i; + float addspeed, accelspeed, currentspeed; + + currentspeed = DotProduct (velocity, wishdir); + addspeed = wishspeed - currentspeed; + if (addspeed <= 0) + return; + accelspeed = (float)(sv_accelerate.value*host_frametime*wishspeed); + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + velocity[i] += accelspeed*wishdir[i]; +} + +void SV_AirAccelerate (vec3_t wishveloc) +{ + int i; + float addspeed, wishspd, accelspeed, currentspeed; + + wishspd = VectorNormalize (wishveloc); + if (wishspd > 30) + wishspd = 30; + currentspeed = DotProduct (velocity, wishveloc); + addspeed = wishspd - currentspeed; + if (addspeed <= 0) + return; +// accelspeed = sv_accelerate.value * host_frametime; + accelspeed = (float)(sv_accelerate.value*wishspeed * host_frametime); + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + velocity[i] += accelspeed*wishveloc[i]; +} + + +void DropPunchAngle (void) +{ + float len; + + len = VectorNormalize (sv_player->v.punchangle); + + len -= (float)(10*host_frametime); + if (len < 0) + len = 0; + VectorScale (sv_player->v.punchangle, len, sv_player->v.punchangle); +} + +/* +=================== +SV_WaterMove + +=================== +*/ +void SV_WaterMove (void) +{ + int i; + vec3_t wishvel; + float speed, newspeed, wishspeed, addspeed, accelspeed; + +// +// user intentions +// + AngleVectors (sv_player->v.v_angle, forward, right, up); + + for (i=0 ; i<3 ; i++) + wishvel[i] = forward[i]*cmd.forwardmove + right[i]*cmd.sidemove; + + if (!cmd.forwardmove && !cmd.sidemove && !cmd.upmove) + wishvel[2] -= 60; // drift towards bottom + else + wishvel[2] += cmd.upmove; + + wishspeed = Length(wishvel); + if (wishspeed > sv_maxspeed.value) + { + VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel); + wishspeed = sv_maxspeed.value; + } + wishspeed *= (float)0.7; + +// +// water friction +// + speed = Length (velocity); + if (speed) + { + newspeed = (float)(speed - host_frametime * speed * sv_friction.value); + if (newspeed < 0) + newspeed = 0; + VectorScale (velocity, newspeed/speed, velocity); + } + else + newspeed = 0; + +// +// water acceleration +// + if (!wishspeed) + return; + + addspeed = wishspeed - newspeed; + if (addspeed <= 0) + return; + + VectorNormalize (wishvel); + accelspeed = (float)(sv_accelerate.value * wishspeed * host_frametime); + if (accelspeed > addspeed) + accelspeed = addspeed; + + for (i=0 ; i<3 ; i++) + velocity[i] += accelspeed * wishvel[i]; +} + +void SV_WaterJump (void) +{ + if (sv.time > sv_player->v.teleport_time + || !sv_player->v.waterlevel) + { + sv_player->v.flags = (float)((int)sv_player->v.flags & ~FL_WATERJUMP); + sv_player->v.teleport_time = 0; + } + sv_player->v.velocity[0] = sv_player->v.movedir[0]; + sv_player->v.velocity[1] = sv_player->v.movedir[1]; +} + + +/* +=================== +SV_AirMove + +=================== +*/ +void SV_AirMove (void) +{ + int i; + vec3_t wishvel; + float fmove, smove; + + AngleVectors (sv_player->v.angles, forward, right, up); + + fmove = cmd.forwardmove; + smove = cmd.sidemove; + +// hack to not let you back into teleporter + if (sv.time < sv_player->v.teleport_time && fmove < 0) + fmove = 0; + + for (i=0 ; i<3 ; i++) + wishvel[i] = forward[i]*fmove + right[i]*smove; + + if ( (int)sv_player->v.movetype != MOVETYPE_WALK) + wishvel[2] = cmd.upmove; + else + wishvel[2] = 0; + + VectorCopy (wishvel, wishdir); + wishspeed = VectorNormalize(wishdir); + if (wishspeed > sv_maxspeed.value) + { + VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel); + wishspeed = sv_maxspeed.value; + } + + if ( sv_player->v.movetype == MOVETYPE_NOCLIP) + { // noclip + VectorCopy (wishvel, velocity); + } + else if ( onground ) + { + SV_UserFriction (); + SV_Accelerate (); + } + else + { // not on ground, so little effect on velocity + SV_AirAccelerate (wishvel); + } +} + +/* +=================== +SV_ClientThink + +the move fields specify an intended velocity in pix/sec +the angle fields specify an exact angular motion in degrees +=================== +*/ +void SV_ClientThink (void) +{ + vec3_t v_angle; + + if (sv_player->v.movetype == MOVETYPE_NONE) + return; + + onground = (int)sv_player->v.flags & FL_ONGROUND; + + origin = sv_player->v.origin; + velocity = sv_player->v.velocity; + + DropPunchAngle (); + +// +// if dead, behave differently +// + if (sv_player->v.health <= 0) + return; + +// +// angles +// show 1/3 the pitch angle and all the roll angle + cmd = host_client->cmd; + angles = sv_player->v.angles; + + VectorAdd (sv_player->v.v_angle, sv_player->v.punchangle, v_angle); + angles[ROLL] = V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4; + if (!sv_player->v.fixangle) + { + angles[PITCH] = -v_angle[PITCH]/3; + angles[YAW] = v_angle[YAW]; + } + + if ( (int)sv_player->v.flags & FL_WATERJUMP ) + { + SV_WaterJump (); + return; + } +// +// walk +// + if ( (sv_player->v.waterlevel >= 2) + && (sv_player->v.movetype != MOVETYPE_NOCLIP) ) + { + SV_WaterMove (); + return; + } + + SV_AirMove (); +} + + +/* +=================== +SV_ReadClientMove +=================== +*/ +void SV_ReadClientMove (usercmd_t *move) +{ + int i; + vec3_t angle; + int bits; + +// read ping time + host_client->ping_times[host_client->num_pings%NUM_PING_TIMES] + = (float)(sv.time - MSG_ReadFloat ()); + host_client->num_pings++; + +// read current angles + for (i=0 ; i<3 ; i++) + angle[i] = MSG_ReadAngle (); + + VectorCopy (angle, host_client->edict->v.v_angle); + +// read movement + move->forwardmove = (float)MSG_ReadShort (); + move->sidemove = (float)MSG_ReadShort (); + move->upmove = (float)MSG_ReadShort (); + +// read buttons + bits = MSG_ReadByte (); + host_client->edict->v.button0 = (float)(bits & 1); + host_client->edict->v.button2 = (float)((bits & 2)>>1); + + i = MSG_ReadByte (); + if (i) + host_client->edict->v.impulse = (float)i; + +#ifdef QUAKE2 +// read light level + host_client->edict->v.light_level = MSG_ReadByte (); +#endif +} + +/* +=================== +SV_ReadClientMessage + +Returns false if the client should be killed +=================== +*/ +qboolean SV_ReadClientMessage (void) +{ + int ret; + int cmd; + char *s; + + do + { +nextmsg: + ret = NET_GetMessage (host_client->netconnection); + if (ret == -1) + { + GpError("SV_ReadClientMes f1",2); + Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n"); + return false; + } + if (!ret){ + return true; + } + + MSG_BeginReading (); + + while (1) + { + if (!host_client->active){ + GpError("SV_ReadClientMes err 1",0); + return false; // a command caused an error + } + + if (msg_badread) + { + GpError("SV_ReadMes err 2",0); + Sys_Printf ("SV_ReadClientMes: badread\n"); + return false; + } + + cmd = MSG_ReadChar (); + + switch (cmd) + { + case -1: + goto nextmsg; // end of message + + default: + GpError("SV_ReadMes err 3",0); + Sys_Printf ("SV_ReadClientMes: unknown command char\n"); + return false; + + case clc_nop: + GpError("cmd = nop",0); +// Sys_Printf ("clc_nop\n"); + break; + + case clc_stringcmd: + s = MSG_ReadString (); + + if (host_client->privileged) + ret = 2; + else + ret = 0; + if (Q_strncasecmp(s, "status", 6) == 0) + ret = 1; + else if (Q_strncasecmp(s, "god", 3) == 0) + ret = 1; + else if (Q_strncasecmp(s, "notarget", 8) == 0) + ret = 1; + else if (Q_strncasecmp(s, "fly", 3) == 0) + ret = 1; + else if (Q_strncasecmp(s, "name", 4) == 0) + ret = 1; + else if (Q_strncasecmp(s, "noclip", 6) == 0) + ret = 1; + else if (Q_strncasecmp(s, "say", 3) == 0) + ret = 1; + else if (Q_strncasecmp(s, "say_team", 8) == 0) + ret = 1; + else if (Q_strncasecmp(s, "tell", 4) == 0) + ret = 1; + else if (Q_strncasecmp(s, "color", 5) == 0) + ret = 1; + else if (Q_strncasecmp(s, "kill", 4) == 0) + ret = 1; + else if (Q_strncasecmp(s, "pause", 5) == 0) + ret = 1; + else if (Q_strncasecmp(s, "spawn", 5) == 0){ + GpError("cmd = spawn",1); + ret = 1; + } + else if (Q_strncasecmp(s, "begin", 5) == 0){ + GpError("cmd = spawn",1); + ret = 1; + } + else if (Q_strncasecmp(s, "prespawn", 8) == 0) + ret = 1; + else if (Q_strncasecmp(s, "kick", 4) == 0) + ret = 1; + else if (Q_strncasecmp(s, "ping", 4) == 0) + ret = 1; + else if (Q_strncasecmp(s, "give", 4) == 0) + ret = 1; + else if (Q_strncasecmp(s, "ban", 3) == 0) + ret = 1; + if (ret == 2) + Cbuf_InsertText (s); + else if (ret == 1) + Cmd_ExecuteString (s, src_client); + else + Con_DPrintf("%s tried to %s\n", host_client->name, s); + break; + + case clc_disconnect: + GpError("cmd = disconnect"); +// Sys_Printf ("SV_ReadClientMessage: client disconnected\n"); + return false; + + case clc_move: + GpError("cmd = move"); + SV_ReadClientMove (&host_client->cmd); + break; + } + } + } while (ret == 1); + + return true; +} + + +/* +================== +SV_RunClients +================== +*/ +void SV_RunClients (void) +{ + int i; + + for (i=0, host_client = svs.clients ; iactive) + continue; + + sv_player = host_client->edict; + + if (!SV_ReadClientMessage ()) + { + GpError("SV_RunClients Drop",2); + SV_DropClient (false); // client misbehaved... + continue; + } + + if (!host_client->spawned) { + // clear client movement until a new packet is received + GpError("!SV_Spawned"); + memset (&host_client->cmd, 0, sizeof(host_client->cmd)); + continue; + } + +// always pause in single player if in console or menus + if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) ) + SV_ClientThink (); + } +} + diff --git a/project/jni/application/quake/source/sys.h b/project/jni/application/quake/source/sys.h new file mode 100644 index 000000000..b3dddaed2 --- /dev/null +++ b/project/jni/application/quake/source/sys.h @@ -0,0 +1,71 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// sys.h -- non-portable functions + +// +// file IO +// + +// returns the file size +// return -1 if file is not present +// the file should be in BINARY mode for stupid OSs that care +int Sys_FileOpenRead (char *path, int *hndl); + +int Sys_FileOpenWrite (char *path); +void Sys_FileClose (int handle); +void Sys_FileSeek (int handle, int position); +int Sys_FileRead (int handle, void *dest, int count); +int Sys_FileWrite (int handle, void *data, int count); +int Sys_FileTime (char *path); +void Sys_mkdir (char *path); + +// +// memory protection +// +void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length); + +// +// system IO +// +void Sys_DebugLog(char *file, char *fmt, ...); + +void Sys_Error (char *error, ...); +// an error will cause the entire program to exit + +void Sys_Printf (char *fmt, ...); +// send text to the console + +void Sys_Quit (void); + +double Sys_FloatTime (void); + +char *Sys_ConsoleInput (void); + +void Sys_Sleep (void); +// called to yield for a little bit so as +// not to hog cpu when paused or debugging + +void Sys_SendKeyEvents (void); +// Perform Key_Event () callbacks until the input que is empty + +void Sys_LowFPPrecision (void); +void Sys_HighFPPrecision (void); +void Sys_SetFPCW (void); + diff --git a/project/jni/application/quake/source/sys_r2-tec.h b/project/jni/application/quake/source/sys_r2-tec.h new file mode 100644 index 000000000..98cef714c --- /dev/null +++ b/project/jni/application/quake/source/sys_r2-tec.h @@ -0,0 +1,30 @@ +/* + Quake(SDL) v1.10 by Rikku2000 + Date: 2010 +*/ + +// SDL +#include +#include + +typedef unsigned char u8; + +void TXT_Printf (TTF_Font *ttf, SDL_Surface *surface, int x, int y, SDL_Color color, char *format, ...) { + char buf[1024]; + SDL_Rect rect; + SDL_Surface *pSurfaceText; + + va_list arg; + + va_start(arg, format); + vsprintf(buf, format, arg); + va_end(arg); + + pSurfaceText = TTF_RenderUTF8_Blended (ttf, buf, color); + + if (pSurfaceText) { + rect.x = x; rect.y = y; + SDL_BlitSurface(pSurfaceText, NULL, surface, &rect); + SDL_FreeSurface(pSurfaceText); + } +} diff --git a/project/jni/application/quake/source/sys_sdl.c b/project/jni/application/quake/source/sys_sdl.c new file mode 100644 index 000000000..6fa2c5eec --- /dev/null +++ b/project/jni/application/quake/source/sys_sdl.c @@ -0,0 +1,514 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __WIN32__ +#include +//#include +#include +#include +#include +#endif + +#include "quakedef.h" +#define DISABLE_CDROM + +qboolean isDedicated; + +int noconinput = 0; + +char *basedir = "."; +char *cachedir = "/tmp"; + +int starttime; + +volatile int sys_checksum; +qboolean isDedicated; +static double lastcurtime = 0.0; +static double curtime = 0.0; +static qboolean sc_return_on_enter = false; +static double pfreq; +static int lowshift; +//HANDLE hinput, houtput; + +//static char *tracking_tag = "Clams & Mooses"; + +#define KEYBUF_SIZE 256 +static int keybuf[KEYBUF_SIZE]; +static int keybuf_head=0; +static int keybuf_tail=0; + +void MaskExceptions (void); +void Sys_InitFloatTime (void); +void Sys_PushFPCW_SetHigh (void); +void Sys_PopFPCW (void); + +cvar_t sys_linerefresh = {"sys_linerefresh","0"};// set for entity display +cvar_t sys_nostdout = {"sys_nostdout","0"}; + +// ======================================================================= +// General routines +// ======================================================================= + +void Sys_DebugNumber(int y, int val) { +} + +void Sys_Printf (char *fmt, ...) +{ + va_list argptr; + char text[1024]; + + va_start (argptr,fmt); + vsprintf (text,fmt,argptr); + va_end (argptr); + fprintf(stderr, "%s", text); + + //Con_Print (text); +} + +void Sys_Quit (void) { + Host_Shutdown(); + exit(0); +} + +void Sys_Init(void) +{ +#if id386 + Sys_SetFPCW(); +#endif +} + +#if !id386 + +/* +================ +Sys_LowFPPrecision +================ +*/ +void Sys_LowFPPrecision (void) +{ +// causes weird problems on Nextstep +} + + +/* +================ +Sys_HighFPPrecision +================ +*/ +void Sys_HighFPPrecision (void) +{ +// causes weird problems on Nextstep +} + +#endif // !id386 + + +void Sys_Error (char *error, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,error); + vsprintf (string,error,argptr); + va_end (argptr); + fprintf(stderr, "Error: %s\n", string); + + Host_Shutdown (); + exit (1); + +} + +void Sys_Warn (char *warning, ...) +{ + va_list argptr; + char string[1024]; + + va_start (argptr,warning); + vsprintf (string,warning,argptr); + va_end (argptr); + fprintf(stderr, "Warning: %s", string); +} + +/* +================ +Sys_PageIn +================ +*/ +void Sys_PageIn (void *ptr, int size) +{ + byte *x; + int /*j, */m, n; + +// touch all the memory to make sure it's there. The 16-page skip is to +// keep Win 95 from thinking we're trying to page ourselves in (we are +// doing that, of course, but there's no reason we shouldn't) + x = (byte *)ptr; + + for (n=0 ; n<4 ; n++) + { + for (m=0 ; m<(size - 16 * 0x1000) ; m += 4) + { + sys_checksum += *(int *)&x[m]; + sys_checksum += *(int *)&x[m + 16 * 0x1000]; + } + } +} + + +/* +=============================================================================== + +FILE IO + +=============================================================================== +*/ + +#define MAX_HANDLES 10 +FILE *sys_handles[MAX_HANDLES]; + +int findhandle (void) +{ + int i; + + for (i=1 ; i= 0 ) { + fclose (sys_handles[handle]); + sys_handles[handle] = NULL; + } +} + +void Sys_FileSeek (int handle, int position) +{ + if ( handle >= 0 ) { + fseek (sys_handles[handle], position, SEEK_SET); + } +} + +int Sys_FileRead (int handle, void *dst, int count) +{ + char *data; + int size, done; + + size = 0; + if ( handle >= 0 ) { + data = dst; + while ( count > 0 ) { + done = fread (data, 1, count, sys_handles[handle]); + if ( done == 0 ) { + break; + } + data += done; + count -= done; + size += done; + } + } + return size; + +} + +int Sys_FileWrite (int handle, void *src, int count) +{ + char *data; + int size, done; + + size = 0; + if ( handle >= 0 ) { + data = src; + while ( count > 0 ) { + done = fread (data, 1, count, sys_handles[handle]); + if ( done == 0 ) { + break; + } + data += done; + count -= done; + size += done; + } + } + return size; +} + +int Sys_FileTime (char *path) { + FILE *f; + + f = fopen(path, "rb"); + if (f) { + fclose(f); + return 1; + } + + return -1; +} + +void Sys_mkdir (char *path) { +#ifdef __WIN32__ + mkdir (path); +#else + mkdir (path, 0777); +#endif +} + +void Sys_DebugLog(char *file, char *fmt, ...) +{ + va_list argptr; + static char data[1024]; + FILE *fp; + + va_start(argptr, fmt); + vsprintf(data, fmt, argptr); + va_end(argptr); + fp = fopen(file, "a"); + fwrite(data, strlen(data), 1, fp); + fclose(fp); +} + +double Sys_FloatTime (void) { +#ifdef __WIN32__ + + static int starttime = 0; + + if ( ! starttime ) + starttime = clock(); + + return (clock()-starttime)*1.0/1024; + +#else + + struct timeval tp; + static int secbase; + + gettimeofday(&tp, NULL); + + if (!secbase) + { + secbase = tp.tv_sec; + return tp.tv_usec/1000000.0; + } + + return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0; + +#endif +} + +// ======================================================================= +// Sleeps for microseconds +// ======================================================================= + +static volatile int oktogo; + +void alarm_handler(int x) +{ + oktogo=1; +} + +byte *Sys_ZoneBase (int *size) +{ + + char *QUAKEOPT = getenv("QUAKEOPT"); + + *size = 0xc00000; + if (QUAKEOPT) + { + while (*QUAKEOPT) + if (tolower(*QUAKEOPT++) == 'm') + { + *size = atof(QUAKEOPT) * 1024*1024; + break; + } + } + return malloc (*size); + +} + +void Sys_LineRefresh(void) +{ +} + +/* +================ +Sys_InitFloatTime +================ +*/ +void Sys_InitFloatTime (void) +{ +/* int j; + + Sys_FloatTime (); + + j = COM_CheckParm("-starttime"); + + if (j) + { + curtime = (double) (Q_atof(com_argv[j+1])); + } + else + { + curtime = 0.0; + } +*/ + curtime = 0.0; + lastcurtime = curtime; +} + + +void Sys_Sleep(void) +{ + SDL_Delay(1); +} + +void floating_point_exception_handler(int whatever) { +// Sys_Warn("floating point exception\n"); + signal(SIGFPE, floating_point_exception_handler); +} + +void moncontrol(int x) { +} + +int main (int c, char **v) { + double time, oldtime, newtime; + quakeparms_t parms; + extern int vcrFile; + extern int recording; + static int frame; + + moncontrol(0); + + signal(SIGFPE, SIG_IGN); + + parms.memsize = 10*1024*1024; + parms.membase = malloc (parms.memsize); + parms.basedir = basedir; + parms.cachedir = cachedir; + + COM_InitArgv(c, v); + parms.argc = com_argc; + parms.argv = com_argv; + + Sys_Init(); + Host_Init(&parms); + + Cvar_RegisterVariable (&sys_nostdout); + + while (1) { + oldtime = Sys_FloatTime () - 0.1; + + newtime = Sys_FloatTime (); + time = newtime - oldtime; + + if (cls.state == ca_dedicated) { + if (time < sys_ticrate.value && (vcrFile == -1 || recording) ) { + SDL_Delay (1); + continue; + } + time = sys_ticrate.value; + } + + if (time > sys_ticrate.value*2) + oldtime = newtime; + else + oldtime += time; + + if (++frame > 10) + moncontrol(1); + + Host_Frame (time); + moncontrol(0); + + if (sys_linerefresh.value) + Sys_LineRefresh (); + } +} + + +/* +================ +Sys_MakeCodeWriteable +================ +*/ +void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length) { + int r; + unsigned long addr; + int psize = getpagesize(); + + fprintf(stderr, "writable code %lx-%lx\n", startaddr, startaddr+length); + + addr = startaddr & ~(psize-1); + + r = mprotect((char*)addr, length + startaddr - addr, 7); + + if (r < 0) + Sys_Error("Protection change failed\n"); + +} + diff --git a/project/jni/application/quake/source/vid.h b/project/jni/application/quake/source/vid.h new file mode 100644 index 000000000..dedf7dece --- /dev/null +++ b/project/jni/application/quake/source/vid.h @@ -0,0 +1,85 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// vid.h -- video driver defs + +#define VID_CBITS 6 +#define VID_GRADES (1 << VID_CBITS) + +// a pixel can be one, two, or four bytes +typedef byte pixel_t; + +typedef struct vrect_s +{ + int x,y,width,height; + struct vrect_s *pnext; +} vrect_t; + +typedef struct +{ + pixel_t *buffer; // invisible buffer + pixel_t *colormap; // 256 * VID_GRADES size + unsigned short *colormap16; // 256 * VID_GRADES size + int fullbright; // index of first fullbright color + unsigned rowbytes; // may be > width if displayed in a window + unsigned width; + unsigned height; + float aspect; // width / height -- < 0 is taller than wide + int numpages; + int recalc_refdef; // if true, recalc vid-based stuff + pixel_t *conbuffer; + int conrowbytes; + unsigned conwidth; + unsigned conheight; + int maxwarpwidth; + int maxwarpheight; + pixel_t *direct; // direct drawing to framebuffer, if not + // NULL +} viddef_t; + +extern viddef_t vid; // global video state +extern unsigned short d_8to16table[256]; +extern unsigned d_8to24table[256]; +extern void (*vid_menudrawfn)(void); +extern void (*vid_menukeyfn)(int key); + +void VID_SetPalette (unsigned char *palette); +// called at startup and after any gamma correction + +void VID_ShiftPalette (unsigned char *palette); +// called for bonus and pain flashes, and for underwater color changes + +void VID_Init (unsigned char *palette); +// Called at startup to set up translation tables, takes 256 8 bit RGB values +// the palette data will go away after the call, so it must be copied off if +// the video driver will need it again + +void VID_Shutdown (void); +// Called at shutdown + +void VID_Update (vrect_t *rects); +// flushes the given rectangles from the view buffer to the screen + +int VID_SetMode (int modenum, unsigned char *palette); +// sets the mode; only used by the Quake engine for resetting to mode 0 (the +// base mode) on memory allocation failures + +void VID_HandlePause (qboolean pause); +// called only on Win32, when pause happens, so the mouse can be released + diff --git a/project/jni/application/quake/source/vid_sdl.c b/project/jni/application/quake/source/vid_sdl.c new file mode 100644 index 000000000..edd9288f0 --- /dev/null +++ b/project/jni/application/quake/source/vid_sdl.c @@ -0,0 +1,576 @@ +// vid_sdl.h -- sdl video driver + +#include +//#include +#include +#include +#include +#include +#include "quakedef.h" +#include "d_local.h" + +// R2-Tec +#include "sys_r2-tec.h" +static TTF_Font *gTTFFont = NULL; + +viddef_t vid; // global video state +unsigned short d_8to16table[256]; + +#define DISABLE_CDROM + +// Quake Screen... +static SDL_Surface *hwscreen = NULL; +static SDL_Surface *screen = NULL; + +int min_vid_width = 320; + +int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes = 0; +byte *VGA_pagebase; + +/* static qboolean mouse_avail; +static float mouse_x, mouse_y; +static int mouse_oldbuttonstate = 0; */ + +//vars for mlook +float start_yaw; +float yaw_modifier=0; + +void drawImage(SDL_Surface *hwscreen, SDL_Surface *image, int x, int y){ + SDL_Rect dstRect; + dstRect.x = x; + dstRect.y = y; + dstRect.w = image->w; + dstRect.h = image->h; + + SDL_BlitSurface(image, NULL, hwscreen, &dstRect); +} + +// No support for option menus +void (*vid_menudrawfn)(void) = NULL; +void (*vid_menukeyfn)(int key) = NULL; + +void VID_SetPalette (unsigned char *palette) { + int i; + SDL_Color colors[256]; + + for ( i=0; i<256; ++i ) { + colors[i].r = *palette++; + colors[i].g = *palette++; + colors[i].b = *palette++; + } + //SDL_SetPalette(screen, SDL_LOGPAL|SDL_PHYSPAL, colors, 0, 256); + SDL_SetColors(screen, colors, 0, 256); +} + +void VID_ShiftPalette (unsigned char *palette) { + VID_SetPalette(palette); +} + +void VID_Init (unsigned char *palette) { + cpu_init(); + + int pnum, chunk; + byte *cache; + int cachesize; + + // Quake(SDL) Menu... + SDL_Surface *background; + + int quit = false; + int option = 0; + int handle = -1; + + TTF_Init(); + gTTFFont = TTF_OpenFont("q_sys/gfx/dpquake.ttf", 16); + + // Load the SDL library + if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) != 0) + Sys_Error("VID: Couldn't load SDL: %s", SDL_GetError()); + + if (!(hwscreen = SDL_SetVideoMode(480, 320, 32, SDL_SWSURFACE|SDL_ASYNCBLIT|SDL_ANYFORMAT|SDL_HWPALETTE))) + Sys_Error("VID: Couldn't set video mode: %s\n", SDL_GetError()); + + // Background + background = IMG_Load("q_sys/gfx/main.png"); + if (!background) { + printf("IMG_Load failed: %s\n", SDL_GetError()); + } + + SDL_Color red = { 210, 0, 0, 0 }; + SDL_Color white = { 245, 245, 245, 0 }; + SDL_Color black = { 0, 0, 0, 0 }; + + // initialize the mouse + SDL_ShowCursor(0); + + while (!quit) { + SDL_FillRect(hwscreen, NULL, SDL_MapRGB(hwscreen->format, 0,0,0)); + + // Background + drawImage(hwscreen, background, 0, 0); + + TXT_Printf(gTTFFont, hwscreen, 1, 3, black, "---------------=======( Quake Menu )=======---------------"); + TXT_Printf(gTTFFont, hwscreen, 0, 2, red, "---------------=======( Quake Menu )=======---------------"); + TXT_Printf(gTTFFont, hwscreen, 21, 31, black, "CPU Overclocking:"); + TXT_Printf(gTTFFont, hwscreen, 20, 30, white, "CPU Overclocking:"); + TXT_Printf(gTTFFont, hwscreen, 20, 79, white, "Modification:"); + TXT_Printf(gTTFFont, hwscreen, 21, 78, black, "Modification:"); + TXT_Printf(gTTFFont, hwscreen, 21, 128, black, "Launch Quake"); + TXT_Printf(gTTFFont, hwscreen, 20, 127, white, "Launch Quake"); + + /* Set current CPU Speed */ + if (r2_cpu == 0) { + TXT_Printf(gTTFFont, hwscreen, 29, 55, black, "- 336 MHz"); + TXT_Printf(gTTFFont, hwscreen, 28, 54, red, "- 336 MHz"); + } else if (r2_cpu == 1) { + TXT_Printf(gTTFFont, hwscreen, 29, 55, black, "- 364 MHz"); + TXT_Printf(gTTFFont, hwscreen, 28, 54, red, "- 364 MHz"); + } else if (r2_cpu == 2) { + TXT_Printf(gTTFFont, hwscreen, 29, 55, black, "- 392 MHz"); + TXT_Printf(gTTFFont, hwscreen, 28, 54, red, "- 392 MHz"); + } else if (r2_cpu == 3) { + TXT_Printf(gTTFFont, hwscreen, 29, 55, black, "- 420 MHz"); + TXT_Printf(gTTFFont, hwscreen, 28, 54, red, "- 420 MHz"); + } + + /* Set current Mod */ + if (r2_mod == 0) { + TXT_Printf(gTTFFont, hwscreen, 29, 103, black, "- Quake (Default)"); + TXT_Printf(gTTFFont, hwscreen, 28, 102, red, "- Quake (Default)"); + } else if (r2_mod == 1) { + TXT_Printf(gTTFFont, hwscreen, 29, 103, black, "- Scourge of Armagon"); + TXT_Printf(gTTFFont, hwscreen, 28, 102, red, "- Scourge of Armagon"); + } else if (r2_mod == 2) { + TXT_Printf(gTTFFont, hwscreen, 29, 103, black, "- Dissolution of Eternity"); + TXT_Printf(gTTFFont, hwscreen, 28, 102, red, "- Dissolution of Eternity"); + } + + /* Set current Option */ + if(option == 0) { + TXT_Printf(gTTFFont, hwscreen, 11, 31, black, ">"); + TXT_Printf(gTTFFont, hwscreen, 10, 30, red, ">"); + } else if(option == 1) { + TXT_Printf(gTTFFont, hwscreen, 11, 79, black, ">"); + TXT_Printf(gTTFFont, hwscreen, 10, 78, red, ">"); + } else if(option == 2) { + TXT_Printf(gTTFFont, hwscreen, 11, 127, black, ">"); + TXT_Printf(gTTFFont, hwscreen, 10, 126, red, ">"); + } + + SDL_Event event; + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_KEYDOWN: + switch (event.key.keysym.sym) { + case SDLK_UP: + option--; + + if(option <= 0) + option = 0; + break; + + case SDLK_LEFT: + if(option == 0) { + r2_cpu--; + + if(r2_cpu <= 0) + r2_cpu = 0; + } else if(option == 1) { + r2_mod--; + + if(r2_mod <= 0) + r2_mod = 0; + } + break; + + case SDLK_DOWN: + option++; + + if(option >= 3) + option = 2; + break; + + case SDLK_RIGHT: + if(option == 0) { + r2_cpu++; + + if(r2_cpu >= 4) + r2_cpu = 3; + } else if(option == 1) { + r2_mod++; + + if(r2_mod >= 3) + r2_mod = 2; + } + break; + + case SDLK_LCTRL: + if(option == 2) { + // Set up display mode (width and height) + vid.width = 480; + vid.height = 320; + + if ((pnum=COM_CheckParm("-winsize"))) { + if (pnum >= com_argc-2) + Sys_Error("VID: -winsize \n"); + + vid.width = Q_atoi(com_argv[pnum+1]); + vid.height = Q_atoi(com_argv[pnum+2]); + + if (!vid.width || !vid.height) + Sys_Error("VID: Bad window width/height\n"); + } + + if (r2_cpu == 1) { + cpu_set_clock(336); + } else if (r2_cpu == 2) { + cpu_set_clock(364); + } else if (r2_cpu == 3) { + cpu_set_clock(392); + } else if (r2_cpu == 3) { + cpu_set_clock(420); + } + + if (r2_mod == 0) { + if (Sys_FileOpenRead("id1/pak0.pak", &handle) < 0) { + Sys_Error("/id1/pak0.pak was not found.\n"); + return; + } else { + Sys_FileClose(handle); + } + } else if (r2_mod == 1) { + if (Sys_FileOpenRead("hipnotic/pak0.pak", &handle) < 0) { + Sys_Error("/hipnotic/pak0.pak was not found.\n"); + return; + } else { + Sys_FileClose(handle); + } + } else if (r2_mod == 2) { + if (Sys_FileOpenRead("rogue/pak0.pak", &handle) < 0) { + Sys_Error("/rogue/pak0.pak was not found.\n"); + return; + } else { + Sys_FileClose(handle); + } + } + + // Initialize display + screen = SDL_CreateRGBSurface(SDL_SWSURFACE, vid.width, vid.height, 8, 0, 0, 0, 0); + quit = true; + } + break; + + default: + break; + } + break; + } + } + + SDL_UpdateRect(hwscreen, 0, 0, 0, 0); + // SDL_Flip(hwscreen); + } + + VID_SetPalette(palette); + SDL_WM_SetCaption("Quake", "quake"); + + // now know everything we need to know about the buffer + VGA_width = vid.conwidth = vid.width; + VGA_height = vid.conheight = vid.height; + vid.aspect = 1.0; + vid.numpages = 1; + vid.colormap = host_colormap; + vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048)); + VGA_pagebase = vid.buffer = screen->pixels; + VGA_rowbytes = vid.rowbytes = screen->pitch; + vid.conbuffer = vid.buffer; + vid.conrowbytes = vid.rowbytes; + vid.direct = 0; + + // allocate z buffer and surface cache + chunk = vid.width * vid.height * sizeof (*d_pzbuffer); + cachesize = D_SurfaceCacheForRes (vid.width, vid.height); + chunk += cachesize; + d_pzbuffer = Hunk_HighAllocName(chunk, "video"); + + if (d_pzbuffer == NULL) + Sys_Error ("Not enough memory for video mode\n"); + + // initialize the cache memory + cache = (byte *) d_pzbuffer + vid.width * vid.height * sizeof (*d_pzbuffer); + D_InitCaches (cache, cachesize); +} + +void VID_Shutdown (void) { + SDL_Quit(); +} + +void VID_Update (vrect_t *rects) { + SDL_Rect *sdlrects; + int n, i; + vrect_t *rect; + + // Two-pass system, since Quake doesn't do it the SDL way... + + // First, count the number of rectangles + n = 0; + for (rect = rects; rect; rect = rect->pnext) + ++n; + + // Second, copy them to SDL rectangles and update + if (!(sdlrects = (SDL_Rect *)alloca(n*sizeof(*sdlrects)))) + Sys_Error("Out of memory"); + i = 0; + + for (rect = rects; rect; rect = rect->pnext) { + sdlrects[i].x = rect->x; + sdlrects[i].y = rect->y; + sdlrects[i].w = rect->width; + sdlrects[i].h = rect->height; + ++i; + } + + SDL_Flip(screen); + SDL_BlitSurface(screen, 0, hwscreen, 0); + SDL_Flip(hwscreen); +} + +/* +================ +D_BeginDirectRect +================ +*/ +void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) +{ + Uint8 *offset; + + + if (!screen) return; + if ( x < 0 ) x = screen->w+x-1; + offset = (Uint8 *)screen->pixels + y*screen->pitch + x; + while ( height-- ) + { + memcpy(offset, pbitmap, width); + offset += screen->pitch; + pbitmap += width; + } +} + + +/* +================ +D_EndDirectRect +================ +*/ +void D_EndDirectRect (int x, int y, int width, int height) +{ + if (!screen) return; + if (x < 0) x = screen->w+x-1; + SDL_UpdateRect(screen, x, y, width, height); +} + + +/* +================ +Sys_SendKeyEvents +================ +*/ + +void Sys_SendKeyEvents(void) +{ + SDL_Event event; + int sym, state; + int modstate; + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_KEYDOWN: + case SDL_KEYUP: + sym = event.key.keysym.sym; + state = event.key.state; + modstate = SDL_GetModState(); + switch(sym) + { + case SDLK_DELETE: sym = K_DEL; break; + case SDLK_BACKSPACE: sym = K_BACKSPACE; break; + case SDLK_F1: sym = K_F1; break; + case SDLK_F2: sym = K_F2; break; + case SDLK_F3: sym = K_F3; break; + case SDLK_F4: sym = K_F4; break; + case SDLK_F5: sym = K_F5; break; + case SDLK_F6: sym = K_F6; break; + case SDLK_F7: sym = K_F7; break; + case SDLK_F8: sym = K_F8; break; + case SDLK_F9: sym = K_F9; break; + case SDLK_F10: sym = K_F10; break; + case SDLK_F11: sym = K_F11; break; + case SDLK_F12: sym = K_F12; break; + case SDLK_BREAK: + case SDLK_PAUSE: sym = K_PAUSE; break; + case SDLK_UP: sym = K_UPARROW; break; + case SDLK_DOWN: sym = K_DOWNARROW; break; + case SDLK_RIGHT: sym = K_RIGHTARROW; break; + case SDLK_LEFT: sym = K_LEFTARROW; break; + case SDLK_INSERT: sym = K_INS; break; + case SDLK_HOME: sym = K_HOME; break; + case SDLK_END: sym = K_END; break; + case SDLK_PAGEUP: sym = K_PGUP; break; + case SDLK_PAGEDOWN: sym = K_PGDN; break; + case SDLK_RSHIFT: + case SDLK_LSHIFT: sym = K_SHIFT; break; + case SDLK_RCTRL: + case SDLK_LCTRL: sym = K_CTRL; break; + case SDLK_RALT: + case SDLK_LALT: sym = K_ALT; break; + case SDLK_KP0: + if(modstate & KMOD_NUM) sym = K_INS; + else sym = SDLK_0; + break; + case SDLK_KP1: + if(modstate & KMOD_NUM) sym = K_END; + else sym = SDLK_1; + break; + case SDLK_KP2: + if(modstate & KMOD_NUM) sym = K_DOWNARROW; + else sym = SDLK_2; + break; + case SDLK_KP3: + if(modstate & KMOD_NUM) sym = K_PGDN; + else sym = SDLK_3; + break; + case SDLK_KP4: + if(modstate & KMOD_NUM) sym = K_LEFTARROW; + else sym = SDLK_4; + break; + case SDLK_KP5: sym = SDLK_5; break; + case SDLK_KP6: + if(modstate & KMOD_NUM) sym = K_RIGHTARROW; + else sym = SDLK_6; + break; + case SDLK_KP7: + if(modstate & KMOD_NUM) sym = K_HOME; + else sym = SDLK_7; + break; + case SDLK_KP8: + if(modstate & KMOD_NUM) sym = K_UPARROW; + else sym = SDLK_8; + break; + case SDLK_KP9: + if(modstate & KMOD_NUM) sym = K_PGUP; + else sym = SDLK_9; + break; + case SDLK_KP_PERIOD: + if(modstate & KMOD_NUM) sym = K_DEL; + else sym = SDLK_PERIOD; + break; + case SDLK_KP_DIVIDE: sym = SDLK_SLASH; break; + case SDLK_KP_MULTIPLY: sym = SDLK_ASTERISK; break; + case SDLK_KP_MINUS: sym = SDLK_MINUS; break; + case SDLK_KP_PLUS: sym = SDLK_PLUS; break; + case SDLK_KP_ENTER: sym = SDLK_RETURN; break; + case SDLK_KP_EQUALS: sym = SDLK_EQUALS; break; + } + // If we're not directly handled and still above 255 + // just force it to 0 + if(sym > 255) sym = 0; + Key_Event(sym, state); + break; + + /* case SDL_MOUSEMOTION: + if ( (event.motion.x != (vid.width/2)) || + (event.motion.y != (vid.height/2)) ) { + mouse_x = event.motion.xrel*10; + mouse_y = event.motion.yrel*10; + if ( (event.motion.x < ((vid.width/2)-(vid.width/4))) || + (event.motion.x > ((vid.width/2)+(vid.width/4))) || + (event.motion.y < ((vid.height/2)-(vid.height/4))) || + (event.motion.y > ((vid.height/2)+(vid.height/4))) ) { + SDL_WarpMouse(vid.width/2, vid.height/2); + } + } + break; */ + + case SDL_QUIT: + CL_Disconnect (); + Host_ShutdownServer(false); + Sys_Quit (); + break; + default: + break; + } + } +} + +void IN_Init (void) { + /* if ( COM_CheckParm ("-nomouse") ) + return; + + mouse_x = mouse_y = 0.0; + mouse_avail = 1; */ +} + +void IN_Shutdown (void) { + // mouse_avail = 0; +} + +void IN_Commands (void) { + /* int i; + int mouse_buttonstate; + + if (!mouse_avail) + return; + + i = SDL_GetMouseState(NULL, NULL); */ + /* Quake swaps the second and third buttons */ + /* mouse_buttonstate = (i & ~0x06) | ((i & 0x02)<<1) | ((i & 0x04)>>1); + for (i=0 ; i<3 ; i++) { + if ( (mouse_buttonstate & (1<sidemove += m_side.value * mouse_x; + else + cl.viewangles[YAW] -= m_yaw.value * mouse_x; + if (in_mlook.state & 1) + V_StopPitchDrift (); + + if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) { + cl.viewangles[PITCH] += m_pitch.value * mouse_y; + if (cl.viewangles[PITCH] > 80) + cl.viewangles[PITCH] = 80; + if (cl.viewangles[PITCH] < -70) + cl.viewangles[PITCH] = -70; + } else { + if ((in_strafe.state & 1) && noclip_anglehack) + cmd->upmove -= m_forward.value * mouse_y; + else + cmd->forwardmove -= m_forward.value * mouse_y; + } + mouse_x = mouse_y = 0.0; */ +} + +/* +================ +Sys_ConsoleInput +================ +*/ +char *Sys_ConsoleInput (void) { + return 0; +} + +void GpError(char *text, int hold){ +} diff --git a/project/jni/application/quake/source/view.c b/project/jni/application/quake/source/view.c new file mode 100644 index 000000000..5548c3fcf --- /dev/null +++ b/project/jni/application/quake/source/view.c @@ -0,0 +1,1894 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// view.c -- player eye positioning + +#include "quakedef.h" +#include "r_local.h" + +/* + +The view is allowed to move slightly from it's true position for bobbing, +but if it exceeds 8 pixels linear distance (spherical, not box), the list of +entities sent from the server may not include everything in the pvs, especially +when crossing a water boudnary. + +*/ + +cvar_t lcd_x = {"lcd_x","0"}; +cvar_t lcd_yaw = {"lcd_yaw","0"}; + +cvar_t scr_ofsx = {"scr_ofsx","0", false}; +cvar_t scr_ofsy = {"scr_ofsy","0", false}; +cvar_t scr_ofsz = {"scr_ofsz","0", false}; + +cvar_t cl_rollspeed = {"cl_rollspeed", "200"}; +cvar_t cl_rollangle = {"cl_rollangle", "2.0"}; + +cvar_t cl_bob = {"cl_bob","0.02", false}; +cvar_t cl_bobcycle = {"cl_bobcycle","0.6", false}; +cvar_t cl_bobup = {"cl_bobup","0.5", false}; + +cvar_t v_kicktime = {"v_kicktime", "0.5", false}; +cvar_t v_kickroll = {"v_kickroll", "0.6", false}; +cvar_t v_kickpitch = {"v_kickpitch", "0.6", false}; + +cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", false}; +cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", false}; +cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", false}; +cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", false}; +cvar_t v_iroll_level = {"v_iroll_level", "0.1", false}; +cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", false}; + +cvar_t v_idlescale = {"v_idlescale", "0", false}; + +cvar_t crosshair = {"crosshair", "1", true}; +cvar_t cl_crossx = {"cl_crossx", "-4", false}; +cvar_t cl_crossy = {"cl_crossy", "0", false}; + +cvar_t r_viewmodeloffset = {"r_viewmodeloffset", "5", true}; + +cvar_t gl_cshiftpercent = {"gl_cshiftpercent", "100", false}; + +float v_dmg_time, v_dmg_roll, v_dmg_pitch; + +#ifdef USEFPM +fixedpoint_t v_dmg_timeFPM, v_dmg_rollFPM, v_dmg_pitchFPM; +#endif //USEFPM + +extern int in_forward, in_forward2, in_back; + + +/* +=============== +V_CalcRoll + +Used by view and sv_user +=============== +*/ +vec3_t forward, right, up; + +#ifdef USEFPM +vec3_FPM_t forwardFPM, rightFPM, upFPM; +#endif //USEFPM + +float V_CalcRoll (vec3_t angles, vec3_t velocity) +{ + float sign; + float side; + float value; + + AngleVectors (angles, forward, right, up); + side = DotProduct (velocity, right); + sign = (float)((side < 0 ? -1.0 : 1.0)); + side = (float)fabs(side); + + value = cl_rollangle.value; +// if (cl.inwater) +// value *= 6; + + if (side < cl_rollspeed.value) + side = side * value / cl_rollspeed.value; + else + side = value; + + return side*sign; +} + +#ifdef USEFPM +fixedpoint_t V_CalcRollFPM (vec3_FPM_t angles, vec3_FPM_t velocity) +{ + fixedpoint_t sign; + fixedpoint_t side; + fixedpoint_t value; + fixedpoint_t cl_rollspeed_value = FPM_FROMFLOAT(cl_rollspeed.value); + + AngleVectorsFPM (angles, forwardFPM, rightFPM, upFPM); + side = DotProductFPM (velocity, rightFPM); + sign = side < 0 ? FPM_FROMLONG(-1) : FPM_FROMLONG(1); + side = FPM_ABS(side); + + value = FPM_FROMFLOAT(cl_rollangle.value); +// if (cl.inwater) +// value *= 6; + + if (side < cl_rollspeed_value) { + //Dan: 16.16 overflow / underflow problem area + __int64 i1, i2; + i1=side; + i1*=value; + i1<<=16; + i2=cl_rollspeed_value; + i2<<=16; + i1/=i2; + i1>>=16; + side=(fixedpoint_t)i1; + //side = FPM_DIV(FPM_MUL(side, value), cl_rollspeed_value); + } else + side = value; + + return FPM_MUL(side,sign); +} +#endif //USEFPM + +/* +=============== +V_CalcBob + +=============== +*/ +float V_CalcBob (void) +{ + float bob; + float cycle; + + cycle = (float)(cl.time - (int)(cl.time/cl_bobcycle.value)*cl_bobcycle.value); + cycle /= cl_bobcycle.value; + if (cycle < cl_bobup.value) + cycle = (float)(M_PI * cycle / cl_bobup.value); + else + cycle = (float)(M_PI + M_PI*(cycle-cl_bobup.value)/(1.0 - cl_bobup.value)); + +// bob is proportional to velocity in the xy plane +// (don't count Z, or jumping messes it up) + + bob = (float)(sqrt(cl.velocity[0]*cl.velocity[0] + cl.velocity[1]*cl.velocity[1]) * cl_bob.value); +//Con_Printf ("speed: %5.1f\n", Length(cl.velocity)); + bob = (float)(bob*0.3 + bob*0.7*sin(cycle)); + if (bob > 4) + bob = 4; + else if (bob < -7) + bob = -7; + return bob; + +} + +#ifdef USEFPM +fixedpoint_t V_CalcBobFPM (void) +{ + float bob; + float cycle; + + cycle = (float)(clFPM.time - (int)(clFPM.time/cl_bobcycle.value)*cl_bobcycle.value); + cycle /= cl_bobcycle.value; + if (cycle < cl_bobup.value) + cycle = (float)(M_PI * cycle / cl_bobup.value); + else + cycle = (float)(M_PI + M_PI*(cycle-cl_bobup.value)/(1.0 - cl_bobup.value)); + +// bob is proportional to velocity in the xy plane +// (don't count Z, or jumping messes it up) + + bob = (float)(sqrt(clFPM.velocity[0]*clFPM.velocity[0] + clFPM.velocity[1]*clFPM.velocity[1]) * cl_bob.value); +//Con_Printf ("speed: %5.1f\n", Length(cl.velocity)); + bob = (float)(bob*0.3 + bob*0.7*sin(cycle)); + if (bob > 4) + bob = 4; + else if (bob < -7) + bob = -7; + return FPM_FROMFLOAT(bob); + +} +#endif //USEFPM +//============================================================================= + + +cvar_t v_centermove = {"v_centermove", "0.15", false}; +cvar_t v_centerspeed = {"v_centerspeed","500"}; + + +void V_StartPitchDrift (void) +{ +#if 1 + if (cl.laststop == cl.time) + { + return; // something else is keeping it from drifting + } +#endif + if (cl.nodrift || !cl.pitchvel) + { + cl.pitchvel = v_centerspeed.value; + cl.nodrift = false; + cl.driftmove = 0; + } +} + +#ifdef USEFPM +void V_StartPitchDriftFPM (void) +{ +#if 1 + if (clFPM.laststop == clFPM.time) + { + return; // something else is keeping it from drifting + } +#endif + if (clFPM.nodrift || !clFPM.pitchvel) + { + clFPM.pitchvel = FPM_FROMFLOAT(v_centerspeed.value); + clFPM.nodrift = false; + clFPM.driftmove = 0; + } +} +#endif //USEFPM + +void V_StopPitchDrift (void) +{ + cl.laststop = cl.time; + cl.nodrift = true; + cl.pitchvel = 0; +} + +#ifdef USEFPM +void V_StopPitchDriftFPM (void) +{ + clFPM.laststop = clFPM.time; + clFPM.nodrift = true; + clFPM.pitchvel = 0; +} +#endif //USEFPM + +/* +=============== +V_DriftPitch + +Moves the client pitch angle towards cl.idealpitch sent by the server. + +If the user is adjusting pitch manually, either with lookup/lookdown, +mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped. + +Drifting is enabled when the center view key is hit, mlook is released and +lookspring is non 0, or when +=============== +*/ +#ifdef _WIN32_WCE +extern mouse_down; +#endif + +void V_DriftPitch (void) +{ + float delta, move; + +#ifdef _WIN32_WCE + //Dan East: Pocket Quake specific + //We don't do drift pitch if the user has the stylus down + if (mouse_down) return; +#endif + + if (noclip_anglehack || !cl.onground || cls.demoplayback ) + { + cl.driftmove = 0; + cl.pitchvel = 0; + return; + } + +// don't count small mouse motion + if (cl.nodrift) + { + if ( fabs(cl.cmd.forwardmove) < cl_forwardspeed.value) + cl.driftmove = 0; + else + cl.driftmove += (float)host_frametime; + + if ( cl.driftmove > v_centermove.value) + { + V_StartPitchDrift (); + } + return; + } + + delta = cl.idealpitch - cl.viewangles[PITCH]; + + if (!delta) + { + cl.pitchvel = 0; + return; + } + + move = (float)(host_frametime * cl.pitchvel); + cl.pitchvel += (float)(host_frametime * v_centerspeed.value); + +//Con_Printf ("move: %f (%f)\n", move, host_frametime); + + if (delta > 0) + { + if (move > delta) + { + cl.pitchvel = 0; + move = delta; + } + cl.viewangles[PITCH] += move; + } + else if (delta < 0) + { + if (move > -delta) + { + cl.pitchvel = 0; + move = -delta; + } + cl.viewangles[PITCH] -= move; + } +} + +#ifdef USEFPM +void V_DriftPitchFPM (void) +{ + fixedpoint_t delta, move; + fixedpoint_t host_frametimeFPM=FPM_FROMFLOAT(host_frametime); + + if (noclip_anglehack || !clFPM.onground || cls.demoplayback ) + { + clFPM.driftmove = 0; + clFPM.pitchvel = 0; + return; + } + +// don't count small mouse motion + if (clFPM.nodrift) + { + if ( fabs(FPM_TOFLOAT(clFPM.cmd.forwardmove)) < cl_forwardspeed.value) + clFPM.driftmove = 0; + else + clFPM.driftmove = FPM_ADD(clFPM.driftmove, host_frametimeFPM); + + if ( FPM_TOFLOAT(clFPM.driftmove) > v_centermove.value) + { + V_StartPitchDriftFPM (); + } + return; + } + + delta = FPM_SUB(clFPM.idealpitch, clFPM.viewangles[PITCH]); + + if (!delta) + { + clFPM.pitchvel = 0; + return; + } + + move = FPM_MUL(host_frametimeFPM, clFPM.pitchvel); + clFPM.pitchvel = FPM_ADD(clFPM.pitchvel, FPM_MUL(host_frametimeFPM, FPM_FROMFLOAT(v_centerspeed.value))); + +//Con_Printf ("move: %f (%f)\n", move, host_frametime); + + if (delta > 0) + { + if (move > delta) + { + clFPM.pitchvel = 0; + move = delta; + } + clFPM.viewangles[PITCH] = FPM_ADD(clFPM.viewangles[PITCH], move); + } + else if (delta < 0) + { + if (move > -delta) + { + clFPM.pitchvel = 0; + move = -delta; + } + clFPM.viewangles[PITCH] = FPM_SUB(clFPM.viewangles[PITCH], move); + } +} +#endif //USEFPM + + + +/* +============================================================================== + + PALETTE FLASHES + +============================================================================== +*/ + + +cshift_t cshift_empty = { {130,80,50}, 0 }; +cshift_t cshift_water = { {130,80,50}, 128 }; +cshift_t cshift_slime = { {0,25,5}, 150 }; +cshift_t cshift_lava = { {255,80,0}, 150 }; + +cvar_t v_gamma = {"gamma", "1", true}; + +byte gammatable[256]; // palette is sent through this + +#ifdef GLQUAKE +byte ramps[3][256]; +float v_blend[4]; // rgba 0.0 - 1.0 +#endif // GLQUAKE + +void BuildGammaTable (float g) +{ + int i, inf; + + if (g == 1.0) + { + for (i=0 ; i<256 ; i++) + gammatable[i] = i; + return; + } + + for (i=0 ; i<256 ; i++) + { + inf = (int)(255 * pow ( (i+0.5)/255.5 , g ) + 0.5); + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + gammatable[i] = inf; + } +} + +/* +================= +V_CheckGamma +================= +*/ +qboolean V_CheckGamma (void) +{ + static float oldgammavalue; + + + //Dan: Hard-coded gamma value + // v_gamma.value=0.5; + + if (v_gamma.value == oldgammavalue) + return false; + oldgammavalue = v_gamma.value; + + BuildGammaTable (v_gamma.value); + vid.recalc_refdef = 1; // force a surface cache flush + + return true; +} + + + +/* +=============== +V_ParseDamage +=============== +*/ +void V_ParseDamage (void) +{ + int armor, blood; + vec3_t from; + int i; + vec3_t forward, right, up; + entity_t *ent; + float side; + float count; + + armor = MSG_ReadByte (); + blood = MSG_ReadByte (); + for (i=0 ; i<3 ; i++) + from[i] = MSG_ReadCoord (); + + count = (float)(blood*0.5 + armor*0.5); + if (count < 10) + count = 10; + + cl.faceanimtime = (float)(cl.time + 0.2); // but sbar face into pain frame + + cl.cshifts[CSHIFT_DAMAGE].percent += (int)(3*count); + if (cl.cshifts[CSHIFT_DAMAGE].percent < 0) + cl.cshifts[CSHIFT_DAMAGE].percent = 0; + if (cl.cshifts[CSHIFT_DAMAGE].percent > 150) + cl.cshifts[CSHIFT_DAMAGE].percent = 150; + + if (armor > blood) + { + cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200; + cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100; + cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100; + } + else if (armor) + { + cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220; + cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50; + cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50; + } + else + { + cl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255; + cl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0; + cl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0; + } + +// +// calculate view angle kicks +// + ent = &cl_entities[cl.viewentity]; + + VectorSubtract (from, ent->origin, from); + VectorNormalize (from); + + AngleVectors (ent->angles, forward, right, up); + + side = DotProduct (from, right); + v_dmg_roll = count*side*v_kickroll.value; + + side = DotProduct (from, forward); + v_dmg_pitch = count*side*v_kickpitch.value; + + v_dmg_time = v_kicktime.value; +} + +#ifdef USEFPM +void V_ParseDamageFPM (void) +{ + int armor, blood; + vec3_FPM_t from; + int i; + vec3_FPM_t forward, right, up; + entity_FPM_t *ent; + fixedpoint_t side; + fixedpoint_t count; + + armor = MSG_ReadByte (); + blood = MSG_ReadByte (); + for (i=0 ; i<3 ; i++) + from[i] = FPM_FROMFLOAT(MSG_ReadCoord ()); + + count = FPM_ADD(FPM_MUL(FPM_FROMLONG(blood),FPM_FROMFLOAT(0.5)), FPM_MUL(FPM_FROMLONG(armor),FPM_FROMFLOAT(0.5))); + if (count < FPM_FROMLONG(10)) + count = FPM_FROMLONG(10); + + clFPM.faceanimtime = (float)(clFPM.time + 0.2); // but sbar face into pain frame + + clFPM.cshifts[CSHIFT_DAMAGE].percent += FPM_TOLONG(FPM_MUL(FPM_FROMLONG(3),count)); + if (clFPM.cshifts[CSHIFT_DAMAGE].percent < 0) + clFPM.cshifts[CSHIFT_DAMAGE].percent = 0; + if (clFPM.cshifts[CSHIFT_DAMAGE].percent > 150) + clFPM.cshifts[CSHIFT_DAMAGE].percent = 150; + + if (armor > blood) + { + clFPM.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200; + clFPM.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100; + clFPM.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100; + } + else if (armor) + { + clFPM.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220; + clFPM.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50; + clFPM.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50; + } + else + { + clFPM.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255; + clFPM.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0; + clFPM.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0; + } + +// +// calculate view angle kicks +// + ent = &cl_entitiesFPM[clFPM.viewentity]; + + VectorSubtractFPM (from, ent->origin, from); + VectorNormalizeFPM (from); + + AngleVectorsFPM (ent->angles, forward, right, up); + + side = DotProductFPM (from, right); + v_dmg_rollFPM = FPM_MUL(FPM_MUL(count, side), FPM_FROMFLOAT(v_kickroll.value)); + + side = DotProductFPM (from, forward); + v_dmg_pitchFPM = FPM_MUL(count,FPM_MUL(side,FPM_FROMFLOAT(v_kickpitch.value))); + + v_dmg_timeFPM = FPM_FROMFLOAT(v_kicktime.value); +} +#endif //USEFPM + +/* +================== +V_cshift_f +================== +*/ +void V_cshift_f (void) +{ + cshift_empty.destcolor[0] = atoi(Cmd_Argv(1)); + cshift_empty.destcolor[1] = atoi(Cmd_Argv(2)); + cshift_empty.destcolor[2] = atoi(Cmd_Argv(3)); + cshift_empty.percent = atoi(Cmd_Argv(4)); +} + + +/* +================== +V_BonusFlash_f + +When you run over an item, the server sends this command +================== +*/ +void V_BonusFlash_f (void) +{ + cl.cshifts[CSHIFT_BONUS].destcolor[0] = 215; + cl.cshifts[CSHIFT_BONUS].destcolor[1] = 186; + cl.cshifts[CSHIFT_BONUS].destcolor[2] = 69; + cl.cshifts[CSHIFT_BONUS].percent = 50; +} + +#ifdef USEFPM +void V_BonusFlash_FPM_f (void) +{ + clFPM.cshifts[CSHIFT_BONUS].destcolor[0] = 215; + clFPM.cshifts[CSHIFT_BONUS].destcolor[1] = 186; + clFPM.cshifts[CSHIFT_BONUS].destcolor[2] = 69; + clFPM.cshifts[CSHIFT_BONUS].percent = 50; +} +#endif //USEFPM + +/* +============= +V_SetContentsColor + +Underwater, lava, etc each has a color shift +============= +*/ +void V_SetContentsColor (int contents) +{ + switch (contents) + { + case CONTENTS_EMPTY: + case CONTENTS_SOLID: + cl.cshifts[CSHIFT_CONTENTS] = cshift_empty; + break; + case CONTENTS_LAVA: + cl.cshifts[CSHIFT_CONTENTS] = cshift_lava; + break; + case CONTENTS_SLIME: + cl.cshifts[CSHIFT_CONTENTS] = cshift_slime; + break; + default: + cl.cshifts[CSHIFT_CONTENTS] = cshift_water; + } +} + +#ifdef USEFPM +void V_SetContentsColorFPM (int contents) +{ + switch (contents) + { + case CONTENTS_EMPTY: + case CONTENTS_SOLID: + clFPM.cshifts[CSHIFT_CONTENTS] = cshift_empty; + break; + case CONTENTS_LAVA: + clFPM.cshifts[CSHIFT_CONTENTS] = cshift_lava; + break; + case CONTENTS_SLIME: + clFPM.cshifts[CSHIFT_CONTENTS] = cshift_slime; + break; + default: + clFPM.cshifts[CSHIFT_CONTENTS] = cshift_water; + } +} +#endif //USEFPM +/* +============= +V_CalcPowerupCshift +============= +*/ +void V_CalcPowerupCshift (void) +{ + if (cl.items & IT_QUAD) + { + cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; + cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0; + cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255; + cl.cshifts[CSHIFT_POWERUP].percent = 30; + } + else if (cl.items & IT_SUIT) + { + cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; + cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; + cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0; + cl.cshifts[CSHIFT_POWERUP].percent = 20; + } + else if (cl.items & IT_INVISIBILITY) + { + cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100; + cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100; + cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100; + cl.cshifts[CSHIFT_POWERUP].percent = 100; + } + else if (cl.items & IT_INVULNERABILITY) + { + cl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255; + cl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; + cl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0; + cl.cshifts[CSHIFT_POWERUP].percent = 30; + } + else + cl.cshifts[CSHIFT_POWERUP].percent = 0; +} + +#ifdef USEFPM +void V_CalcPowerupCshiftFPM (void) +{ + if (clFPM.items & IT_QUAD) + { + clFPM.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; + clFPM.cshifts[CSHIFT_POWERUP].destcolor[1] = 0; + clFPM.cshifts[CSHIFT_POWERUP].destcolor[2] = 255; + clFPM.cshifts[CSHIFT_POWERUP].percent = 30; + } + else if (clFPM.items & IT_SUIT) + { + clFPM.cshifts[CSHIFT_POWERUP].destcolor[0] = 0; + clFPM.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; + clFPM.cshifts[CSHIFT_POWERUP].destcolor[2] = 0; + clFPM.cshifts[CSHIFT_POWERUP].percent = 20; + } + else if (clFPM.items & IT_INVISIBILITY) + { + clFPM.cshifts[CSHIFT_POWERUP].destcolor[0] = 100; + clFPM.cshifts[CSHIFT_POWERUP].destcolor[1] = 100; + clFPM.cshifts[CSHIFT_POWERUP].destcolor[2] = 100; + clFPM.cshifts[CSHIFT_POWERUP].percent = 100; + } + else if (clFPM.items & IT_INVULNERABILITY) + { + clFPM.cshifts[CSHIFT_POWERUP].destcolor[0] = 255; + clFPM.cshifts[CSHIFT_POWERUP].destcolor[1] = 255; + clFPM.cshifts[CSHIFT_POWERUP].destcolor[2] = 0; + clFPM.cshifts[CSHIFT_POWERUP].percent = 30; + } + else + clFPM.cshifts[CSHIFT_POWERUP].percent = 0; +} +#endif //USEFPM + +/* +============= +V_CalcBlend +============= +*/ +#ifdef GLQUAKE +//Dan: Not converted +void V_CalcBlend (void) +{ + float r, g, b, a, a2; + int j; + + r = 0; + g = 0; + b = 0; + a = 0; + + for (j=0 ; j 1) + v_blend[3] = 1; + if (v_blend[3] < 0) + v_blend[3] = 0; +} +#endif + +/* +============= +V_UpdatePalette +============= +*/ +#ifdef GLQUAKE +//Dan: not converted +void V_UpdatePalette (void) +{ + int i, j; + qboolean new; + byte *basepal, *newpal; + byte pal[768]; + float r,g,b,a; + int ir, ig, ib; + qboolean force; + + V_CalcPowerupCshift (); + + new = false; + + for (i=0 ; i 255) + ir = 255; + if (ig > 255) + ig = 255; + if (ib > 255) + ib = 255; + + ramps[0][i] = gammatable[ir]; + ramps[1][i] = gammatable[ig]; + ramps[2][i] = gammatable[ib]; + } + + basepal = host_basepal; + newpal = pal; + + for (i=0 ; i<256 ; i++) + { + ir = basepal[0]; + ig = basepal[1]; + ib = basepal[2]; + basepal += 3; + + newpal[0] = ramps[0][ir]; + newpal[1] = ramps[1][ig]; + newpal[2] = ramps[2][ib]; + newpal += 3; + } + + VID_ShiftPalette (pal); +} +#else // !GLQUAKE +void V_UpdatePalette (void) +{ + int i, j; + qboolean new; + byte *basepal,*newpal; + byte pal[768]; + int r,g,b; + qboolean force; + + V_CalcPowerupCshift (); + + new = false; + + for (i=0 ; i>8; + g += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[1]-g))>>8; + b += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[2]-b))>>8; + } + + newpal[0] = gammatable[r]; + newpal[1] = gammatable[g]; + newpal[2] = gammatable[b]; + newpal += 3; + } + + VID_ShiftPalette (pal); + +} + +#ifdef USEFPM +void V_UpdatePaletteFPM (void) +{ + int i, j; + qboolean new; + byte *basepal, *newpal; + byte pal[768]; + int r,g,b; + qboolean force; + + V_CalcPowerupCshiftFPM (); + + new = false; + + for (i=0 ; i>8; + g += (clFPM.cshifts[j].percent*(clFPM.cshifts[j].destcolor[1]-g))>>8; + b += (clFPM.cshifts[j].percent*(clFPM.cshifts[j].destcolor[2]-b))>>8; + } + + newpal[0] = gammatable[r]; + newpal[1] = gammatable[g]; + newpal[2] = gammatable[b]; + newpal += 3; + } + + VID_ShiftPalette(pal); +} +#endif //USEFPM +#endif // !GLQUAKE + + +/* +============================================================================== + + VIEW RENDERING + +============================================================================== +*/ + +float angledelta (float a) +{ + a = anglemod(a); + if (a > 180) + a -= 360; + return a; +} + +#ifdef USEFPM +fixedpoint_t angledeltaFPM (fixedpoint_t a) +{ + a = anglemodFPM(a); + if (a > 180) + a -= 360; + return a; +} +#endif //USEFPM +/* +================== +CalcGunAngle +================== +*/ +void CalcGunAngle (void) +{ + float yaw, pitch, move; + static float oldyaw = 0; + static float oldpitch = 0; + + yaw = r_refdef.viewangles[YAW]; + pitch = -r_refdef.viewangles[PITCH]; + + yaw = (float)(angledelta(yaw - r_refdef.viewangles[YAW]) * 0.4); + if (yaw > 10) + yaw = 10; + if (yaw < -10) + yaw = -10; + pitch = (float)(angledelta(-pitch - r_refdef.viewangles[PITCH]) * 0.4); + if (pitch > 10) + pitch = 10; + if (pitch < -10) + pitch = -10; + move = (float)(host_frametime*20); + if (yaw > oldyaw) + { + if (oldyaw + move < yaw) + yaw = oldyaw + move; + } + else + { + if (oldyaw - move > yaw) + yaw = oldyaw - move; + } + + if (pitch > oldpitch) + { + if (oldpitch + move < pitch) + pitch = oldpitch + move; + } + else + { + if (oldpitch - move > pitch) + pitch = oldpitch - move; + } + + oldyaw = yaw; + oldpitch = pitch; + + cl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw; + cl.viewent.angles[PITCH] = - (r_refdef.viewangles[PITCH] + pitch); + + cl.viewent.angles[ROLL] -= (float)(v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value); + cl.viewent.angles[PITCH] -= (float)(v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value); + cl.viewent.angles[YAW] -= (float)(v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value); +} + +#ifdef USEFPM +void CalcGunAngleFPM (void) +{ + fixedpoint_t yaw, pitch, move; + static fixedpoint_t oldyaw = 0; + static fixedpoint_t oldpitch = 0; + + yaw = r_refdefFPM.viewangles[YAW]; + pitch = -r_refdefFPM.viewangles[PITCH]; + + yaw = angledeltaFPM(FPM_SUB(yaw, FPM_MUL(r_refdefFPM.viewangles[YAW], FPM_FROMFLOAT(0.4)))); + if (yaw > FPM_FROMLONG(10)) + yaw = FPM_FROMLONG(10); + if (yaw < FPM_FROMLONG(-10)) + yaw = FPM_FROMLONG(-10); + pitch = angledeltaFPM(FPM_SUB(-pitch, FPM_MUL(r_refdefFPM.viewangles[PITCH], FPM_FROMFLOAT(0.4)))); + if (pitch > FPM_FROMLONG(10)) + pitch = FPM_FROMLONG(10); + if (pitch < FPM_FROMLONG(-10)) + pitch = FPM_FROMLONG(-10); + move = FPM_MUL(FPM_FROMFLOAT(host_frametime),FPM_FROMLONG(20)); + if (yaw > oldyaw) + { + if (FPM_ADD(oldyaw, move) < yaw) + yaw = FPM_ADD(oldyaw, move); + } + else + { + if (FPM_SUB(oldyaw, move) > yaw) + yaw = FPM_SUB(oldyaw, move); + } + + if (pitch > oldpitch) + { + if (FPM_ADD(oldpitch, move) < pitch) + pitch = FPM_ADD(oldpitch, move); + } + else + { + if (FPM_SUB(oldpitch, move) > pitch) + pitch = FPM_SUB(oldpitch, move); + } + + oldyaw = yaw; + oldpitch = pitch; + + clFPM.viewent.angles[YAW] = FPM_ADD(r_refdefFPM.viewangles[YAW], yaw); + clFPM.viewent.angles[PITCH] = - FPM_ADD(r_refdefFPM.viewangles[PITCH], pitch); + + clFPM.viewent.angles[ROLL] = FPM_SUB(clFPM.viewent.angles[ROLL], FPM_FROMFLOAT(v_idlescale.value * sin(clFPM.time*v_iroll_cycle.value) * v_iroll_level.value)); + clFPM.viewent.angles[PITCH] = FPM_SUB(clFPM.viewent.angles[PITCH], FPM_FROMFLOAT(v_idlescale.value * sin(clFPM.time*v_ipitch_cycle.value) * v_ipitch_level.value)); + clFPM.viewent.angles[YAW] = FPM_SUB(clFPM.viewent.angles[YAW], FPM_FROMFLOAT(v_idlescale.value * sin(clFPM.time*v_iyaw_cycle.value) * v_iyaw_level.value)); +} +#endif //USEFPM +/* +============== +V_BoundOffsets +============== +*/ +void V_BoundOffsets (void) +{ + entity_t *ent; + + ent = &cl_entities[cl.viewentity]; + +// absolutely bound refresh reletive to entity clipping hull +// so the view can never be inside a solid wall + + if (r_refdef.vieworg[0] < ent->origin[0] - 14) + r_refdef.vieworg[0] = ent->origin[0] - 14; + else if (r_refdef.vieworg[0] > ent->origin[0] + 14) + r_refdef.vieworg[0] = ent->origin[0] + 14; + if (r_refdef.vieworg[1] < ent->origin[1] - 14) + r_refdef.vieworg[1] = ent->origin[1] - 14; + else if (r_refdef.vieworg[1] > ent->origin[1] + 14) + r_refdef.vieworg[1] = ent->origin[1] + 14; + if (r_refdef.vieworg[2] < ent->origin[2] - 22) + r_refdef.vieworg[2] = ent->origin[2] - 22; + else if (r_refdef.vieworg[2] > ent->origin[2] + 30) + r_refdef.vieworg[2] = ent->origin[2] + 30; +} + +#ifdef USEFPM +void V_BoundOffsetsFPM (void) +{ + entity_FPM_t *ent; + + ent = &cl_entitiesFPM[clFPM.viewentity]; + +// absolutely bound refresh reletive to entity clipping hull +// so the view can never be inside a solid wall + + if (r_refdefFPM.vieworg[0] < FPM_SUB(ent->origin[0], FPM_FROMLONG(14))) + r_refdefFPM.vieworg[0] = FPM_SUB(ent->origin[0], FPM_FROMLONG(14)); + else if (r_refdefFPM.vieworg[0] > FPM_ADD(ent->origin[0], FPM_FROMLONG(14))) + r_refdefFPM.vieworg[0] = FPM_ADD(ent->origin[0], FPM_FROMLONG(14)); + if (r_refdefFPM.vieworg[1] < FPM_SUB(ent->origin[1], FPM_FROMLONG(14))) + r_refdefFPM.vieworg[1] = FPM_SUB(ent->origin[1], FPM_FROMLONG(14)); + else if (r_refdefFPM.vieworg[1] > FPM_ADD(ent->origin[1], FPM_FROMLONG(14))) + r_refdefFPM.vieworg[1] = FPM_ADD(ent->origin[1], FPM_FROMLONG(14)); + if (r_refdefFPM.vieworg[2] < FPM_SUB(ent->origin[2], FPM_FROMLONG(22))) + r_refdefFPM.vieworg[2] = FPM_SUB(ent->origin[2], FPM_FROMLONG(22)); + else if (r_refdefFPM.vieworg[2] > FPM_ADD(ent->origin[2], FPM_FROMLONG(30))) + r_refdefFPM.vieworg[2] = FPM_ADD(ent->origin[2], FPM_FROMLONG(30)); +} +#endif //USEFPM +/* +============== +V_AddIdle + +Idle swaying +============== +*/ +void V_AddIdle (void) +{ + r_refdef.viewangles[ROLL] += (float)(v_idlescale.value * sin(cl.time*v_iroll_cycle.value) * v_iroll_level.value); + r_refdef.viewangles[PITCH] += (float)(v_idlescale.value * sin(cl.time*v_ipitch_cycle.value) * v_ipitch_level.value); + r_refdef.viewangles[YAW] += (float)(v_idlescale.value * sin(cl.time*v_iyaw_cycle.value) * v_iyaw_level.value); +} + +#ifdef USEFPM +void V_AddIdleFPM (void) +{ + r_refdefFPM.viewangles[ROLL] = FPM_ADD(r_refdefFPM.viewangles[ROLL], FPM_FROMFLOAT(v_idlescale.value * sin(clFPM.time*v_iroll_cycle.value) * v_iroll_level.value)); + r_refdefFPM.viewangles[PITCH] = FPM_ADD(r_refdefFPM.viewangles[PITCH], FPM_FROMFLOAT(v_idlescale.value * sin(clFPM.time*v_ipitch_cycle.value) * v_ipitch_level.value)); + r_refdefFPM.viewangles[YAW] = FPM_ADD(r_refdefFPM.viewangles[YAW], FPM_FROMFLOAT(v_idlescale.value * sin(clFPM.time*v_iyaw_cycle.value) * v_iyaw_level.value)); +} +#endif //USEFPM +/* +============== +V_CalcViewRoll + +Roll is induced by movement and damage +============== +*/ +void V_CalcViewRoll (void) +{ + float side; + + side = V_CalcRoll (cl_entities[cl.viewentity].angles, cl.velocity); + r_refdef.viewangles[ROLL] += side; + + if (v_dmg_time > 0) + { + r_refdef.viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll; + r_refdef.viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch; + v_dmg_time -= (float)host_frametime; + } + + if (cl.stats[STAT_HEALTH] <= 0) + { + r_refdef.viewangles[ROLL] = 80; // dead view angle + return; + } + +} + +#ifdef USEFPM +void V_CalcViewRollFPM (void) +{ + fixedpoint_t side; + + side = V_CalcRollFPM (cl_entitiesFPM[clFPM.viewentity].angles, clFPM.velocity); + r_refdefFPM.viewangles[ROLL] = FPM_ADD(r_refdefFPM.viewangles[ROLL], side); + + if (v_dmg_time > 0) + { + r_refdefFPM.viewangles[ROLL] = FPM_ADD(r_refdefFPM.viewangles[ROLL], FPM_FROMFLOAT(v_dmg_time/v_kicktime.value*v_dmg_roll)); + r_refdefFPM.viewangles[PITCH] = FPM_ADD(r_refdefFPM.viewangles[PITCH], FPM_FROMFLOAT(v_dmg_time/v_kicktime.value*v_dmg_pitch)); + v_dmg_time -= (float)host_frametime; + } + + if (clFPM.stats[STAT_HEALTH] <= 0) + { + r_refdefFPM.viewangles[ROLL] = FPM_FROMLONG(80); // dead view angle + return; + } +} +#endif //USEFPM + +/* +================== +V_CalcIntermissionRefdef + +================== +*/ +void V_CalcIntermissionRefdef (void) +{ + entity_t *ent, *view; + float old; + +// ent is the player model (visible when out of body) + ent = &cl_entities[cl.viewentity]; +// view is the weapon model (only visible from inside body) + view = &cl.viewent; + + VectorCopy (ent->origin, r_refdef.vieworg); + VectorCopy (ent->angles, r_refdef.viewangles); + view->model = NULL; + +// allways idle in intermission + old = v_idlescale.value; + v_idlescale.value = 1; + V_AddIdle (); + v_idlescale.value = old; +} + +#ifdef USEFPM +void V_CalcIntermissionRefdefFPM (void) +{ + entity_FPM_t *ent, *view; + float old; + +// ent is the player model (visible when out of body) + ent = &cl_entitiesFPM[clFPM.viewentity]; +// view is the weapon model (only visible from inside body) + view = &clFPM.viewent; + + VectorCopy (ent->origin, r_refdefFPM.vieworg); + VectorCopy (ent->angles, r_refdefFPM.viewangles); + view->model = NULL; + +// allways idle in intermission + old = v_idlescale.value; + v_idlescale.value = 1; + V_AddIdleFPM (); + v_idlescale.value = old; +} +#endif //USEFPM +/* +================== +V_CalcRefdef + +================== +*/ +extern float yaw_modifier; +extern float start_yaw; +void V_CalcRefdef (void) +{ + entity_t *ent, *view; + int i; + vec3_t forward, right, up; + vec3_t angles; + float bob; + static float oldz = 0; + + //Dan East: + //Here we handle automatic yaw rotation when the stylus reaches the edge of the screen + cl.viewangles[YAW]+=yaw_modifier; + start_yaw+=yaw_modifier; + + V_DriftPitch (); + +// ent is the player model (visible when out of body) + ent = &cl_entities[cl.viewentity]; +// view is the weapon model (only visible from inside body) + view = &cl.viewent; + + +// transform the view offset by the model's matrix to get the offset from +// model origin for the view + ent->angles[YAW] = cl.viewangles[YAW]; // the model should face + // the view dir + ent->angles[PITCH] = -cl.viewangles[PITCH]; // the model should face + // the view dir + + + bob = V_CalcBob (); + +// refresh position + VectorCopy (ent->origin, r_refdef.vieworg); + r_refdef.vieworg[2] += cl.viewheight + bob; + +// never let it sit exactly on a node line, because a water plane can +// dissapear when viewed with the eye exactly on it. +// the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis + r_refdef.vieworg[0] += 1.0/32; + r_refdef.vieworg[1] += 1.0/32; + r_refdef.vieworg[2] += 1.0/32; + + VectorCopy (cl.viewangles, r_refdef.viewangles); + V_CalcViewRoll (); + V_AddIdle (); + +// offsets + angles[PITCH] = -ent->angles[PITCH]; // because entity pitches are + // actually backward + angles[YAW] = ent->angles[YAW]; + angles[ROLL] = ent->angles[ROLL]; + + AngleVectors (angles, forward, right, up); + + for (i=0 ; i<3 ; i++) + r_refdef.vieworg[i] += scr_ofsx.value*forward[i] + + scr_ofsy.value*right[i] + + scr_ofsz.value*up[i]; + + + V_BoundOffsets (); + +// set up gun position + VectorCopy (cl.viewangles, view->angles); + + CalcGunAngle (); + + VectorCopy (ent->origin, view->origin); + view->origin[2] += cl.viewheight; + +#if 0 + for (i=0 ; i<3 ; i++) + { + view->origin[i] += forward[i]*bob*0.4; + // view->origin[i] += right[i]*bob*0.4; + // view->origin[i] += up[i]*bob*0.8; + } + view->origin[2] += bob; +#endif + +#if 1 + VectorCopy (r_refdef.vieworg, view->origin); + VectorMA (view->origin, bob * 0.4, forward, view->origin); + + if (r_viewmodeloffset.string[0]) { + float offset[3]; + int size = sizeof(offset)/sizeof(offset[0]); + + ParseFloats(r_viewmodeloffset.string, offset, &size); + VectorMA (view->origin, offset[0], right, view->origin); + VectorMA (view->origin, -offset[1], up, view->origin); + VectorMA (view->origin, offset[2], forward, view->origin); + } +#endif + +// fudge position around to keep amount of weapon visible +// roughly equal with different FOV + +#if 0 + if (cl.model_precache[cl.stats[STAT_WEAPON]] && strcmp (cl.model_precache[cl.stats[STAT_WEAPON]]->name, "progs/v_shot2.mdl")) +#endif + if (scr_viewsize.value == 110) + view->origin[2] += 1; + else if (scr_viewsize.value == 100) + view->origin[2] += 2; + else if (scr_viewsize.value == 90) + view->origin[2] += 1; + else if (scr_viewsize.value == 80) + view->origin[2] += 0.5; + + view->model = cl.model_precache[cl.stats[STAT_WEAPON]]; + view->frame = cl.stats[STAT_WEAPONFRAME]; + view->colormap = vid.colormap; + +// set up the refresh position + VectorAdd (r_refdef.viewangles, cl.punchangle, r_refdef.viewangles); + +// smooth out stair step ups +if (cl.onground && ent->origin[2] - oldz > 0) +{ + float steptime; + + steptime = (float)(cl.time - cl.oldtime); + if (steptime < 0) +//FIXME I_Error ("steptime < 0"); + steptime = 0; + + oldz += steptime * 80; + if (oldz > ent->origin[2]) + oldz = ent->origin[2]; + if (ent->origin[2] - oldz > 12) + oldz = ent->origin[2] - 12; + r_refdef.vieworg[2] += oldz - ent->origin[2]; + view->origin[2] += oldz - ent->origin[2]; +} +else + oldz = ent->origin[2]; + + if (chase_active.value) + Chase_Update (); +} + +#ifdef USEFPM +void V_CalcRefdefFPM (void) +{ + entity_FPM_t *ent, *view; + int i; + vec3_FPM_t forward, right, up; + vec3_FPM_t angles; + fixedpoint_t bob; + static fixedpoint_t oldz = 0; + + V_DriftPitchFPM (); + +// ent is the player model (visible when out of body) + ent = &cl_entitiesFPM[clFPM.viewentity]; +// view is the weapon model (only visible from inside body) + view = &clFPM.viewent; + + +// transform the view offset by the model's matrix to get the offset from +// model origin for the view + ent->angles[YAW] = clFPM.viewangles[YAW]; // the model should face + // the view dir + ent->angles[PITCH] = -clFPM.viewangles[PITCH]; // the model should face + // the view dir + + + bob = V_CalcBobFPM (); + +// refresh position + VectorCopy (ent->origin, r_refdefFPM.vieworg); + r_refdefFPM.vieworg[2] = FPM_ADD(r_refdefFPM.vieworg[2], FPM_ADD(clFPM.viewheight, bob)); + +// never let it sit exactly on a node line, because a water plane can +// dissapear when viewed with the eye exactly on it. +// the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis + r_refdefFPM.vieworg[0] = FPM_ADD(r_refdefFPM.vieworg[0], FPM_FROMFLOAT(1.0/32)); + r_refdefFPM.vieworg[1] = FPM_ADD(r_refdefFPM.vieworg[1], FPM_FROMFLOAT(1.0/32)); + r_refdefFPM.vieworg[2] = FPM_ADD(r_refdefFPM.vieworg[2], FPM_FROMFLOAT(1.0/32)); + + VectorCopy (clFPM.viewangles, r_refdefFPM.viewangles); + V_CalcViewRollFPM (); + V_AddIdleFPM (); + +// offsets + angles[PITCH] = -ent->angles[PITCH]; // because entity pitches are + // actually backward + angles[YAW] = ent->angles[YAW]; + angles[ROLL] = ent->angles[ROLL]; + + AngleVectorsFPM (angles, forward, right, up); + + for (i=0 ; i<3 ; i++) + r_refdefFPM.vieworg[i] = FPM_ADD(r_refdefFPM.vieworg[i], FPM_ADD3(FPM_MUL(FPM_FROMFLOAT(scr_ofsx.value),forward[i]), + FPM_MUL(FPM_FROMFLOAT(scr_ofsy.value),right[i]), + FPM_MUL(FPM_FROMFLOAT(scr_ofsz.value),up[i]))); + + + V_BoundOffsetsFPM (); + +// set up gun position + VectorCopy (clFPM.viewangles, view->angles); + + CalcGunAngleFPM (); + + VectorCopy (ent->origin, view->origin); + view->origin[2] = FPM_ADD(view->origin[2], clFPM.viewheight); + + for (i=0 ; i<3 ; i++) + { + view->origin[i] += FPM_ADD(view->origin[i], (FPM_MUL(FPM_MUL(forward[i],bob),FPM_FROMFLOAT(0.4)))); +// view->origin[i] += right[i]*bob*0.4; +// view->origin[i] += up[i]*bob*0.8; + } + view->origin[2] = FPM_ADD(view->origin[2], bob); + +// fudge position around to keep amount of weapon visible +// roughly equal with different FOV + +#if 0 + //Dan: Not converted + if (cl.model_precache[cl.stats[STAT_WEAPON]] && strcmp (cl.model_precache[cl.stats[STAT_WEAPON]]->name, "progs/v_shot2.mdl")) +#endif + if (scr_viewsize.value == 110) + FPM_INC(view->origin[2]); + else if (scr_viewsize.value == 100) + view->origin[2]=FPM_ADD(view->origin[2], FPM_FROMLONG(2)); + else if (scr_viewsize.value == 90) + FPM_INC(view->origin[2]); + else if (scr_viewsize.value == 80) + view->origin[2]=FPM_ADD(view->origin[2], FPM_FROMFLOAT(0.5)); + + view->model = clFPM.model_precache[clFPM.stats[STAT_WEAPON]]; + view->frame = clFPM.stats[STAT_WEAPONFRAME]; + view->colormap = vid.colormap; + +// set up the refresh position + VectorAdd (r_refdefFPM.viewangles, clFPM.punchangle, r_refdefFPM.viewangles); + + // smooth out stair step ups + if (clFPM.onground && ent->origin[2] - oldz > 0) + { + fixedpoint_t steptime; + + steptime = FPM_FROMFLOAT(clFPM.time - clFPM.oldtime); + if (steptime < 0) + //FIXME I_Error ("steptime < 0"); + steptime = 0; + + oldz = FPM_ADD(oldz, FPM_MUL(steptime, FPM_FROMLONG(80))); + if (oldz > ent->origin[2]) + oldz = ent->origin[2]; + if (FPM_SUB(ent->origin[2], oldz) > FPM_FROMLONG(12)) + oldz = FPM_SUB(ent->origin[2], FPM_FROMLONG(12)); + r_refdefFPM.vieworg[2] = FPM_ADD(r_refdefFPM.vieworg[2], FPM_SUB(oldz, ent->origin[2])); + view->origin[2] = FPM_ADD(view->origin[2], FPM_SUB(oldz, ent->origin[2])); + } + else + oldz = ent->origin[2]; + + if (chase_active.value) + Chase_UpdateFPM (); +} +#endif //USEFPM + +/* +================== +V_RenderView + +The player's clipping box goes from (-16 -16 -24) to (16 16 32) from +the entity origin, so any view position inside that will be valid +================== +*/ +extern vrect_t scr_vrect; + +void V_RenderView (void) +{ + + if (con_forcedup) + return; + +// don't allow cheats in multiplayer + if (cl.maxclients > 1) + { + Cvar_Set ("scr_ofsx", "0"); + Cvar_Set ("scr_ofsy", "0"); + Cvar_Set ("scr_ofsz", "0"); + } + + if (cl.intermission) + { // intermission / finale rendering + V_CalcIntermissionRefdef (); + } + else + { +// if (!cl.paused /* && (sv.maxclients > 1 || key_dest == key_game) */ ) + V_CalcRefdef (); + } + + + R_PushDlights (); // 0.4 fps increase if removed + + if (lcd_x.value) + { + // + // render two interleaved views + // + int i; + + vid.rowbytes <<= 1; + vid.aspect *= 0.5; + + r_refdef.viewangles[YAW] -= lcd_yaw.value; + for (i=0 ; i<3 ; i++) + r_refdef.vieworg[i] -= right[i]*lcd_x.value; + + R_RenderView (); + + vid.buffer += vid.rowbytes>>1; + + R_PushDlights (); + + r_refdef.viewangles[YAW] += lcd_yaw.value*2; + for (i=0 ; i<3 ; i++) + r_refdef.vieworg[i] += 2*right[i]*lcd_x.value; + R_RenderView (); + + vid.buffer -= vid.rowbytes>>1; + + r_refdef.vrect.height <<= 1; + + vid.rowbytes >>= 1; + vid.aspect *= 2; + } + else + { + + R_RenderView (); + + } + + +#ifndef GLQUAKE + + if ((crosshair.value==1) || (crosshair.value>4)) { + Draw_Character ((int)(scr_vrect.x + scr_vrect.width/2 + cl_crossx.value), + (int)(scr_vrect.y + scr_vrect.height/2 + cl_crossy.value), '+'); + } + + if (crosshair.value==2) { + Draw_Character ((int)(scr_vrect.x + scr_vrect.width/2 + cl_crossx.value), + (int)(scr_vrect.y + scr_vrect.height/2 + cl_crossy.value), 'x'); + } + + if (crosshair.value==3) { + Draw_Character ((int)(scr_vrect.x + scr_vrect.width/2 + cl_crossx.value), + (int)(scr_vrect.y + scr_vrect.height/2 + cl_crossy.value), 'X'); + } + + if (crosshair.value==4) { + Draw_Character ((int)(scr_vrect.x + scr_vrect.width/2 + cl_crossx.value), + (int)(scr_vrect.y + scr_vrect.height/2 + cl_crossy.value), '.'); + } +#endif + + +} + +#ifdef USEFPM +void V_RenderViewFPM (void) +{ + if (con_forcedup) + return; + +// don't allow cheats in multiplayer + if (clFPM.maxclients > 1) + { + Cvar_Set ("scr_ofsx", "0"); + Cvar_Set ("scr_ofsy", "0"); + Cvar_Set ("scr_ofsz", "0"); + } + + if (clFPM.intermission) + { // intermission / finale rendering + V_CalcIntermissionRefdefFPM (); + } + else + { + if (!clFPM.paused /* && (sv.maxclients > 1 || key_dest == key_game) */ ) + V_CalcRefdefFPM (); + } + + R_PushDlightsFPM (); + + if (lcd_x.value) + { + // + // render two interleaved views + // + int i; + + vid.rowbytes <<= 1; + vid.aspect *= 0.5; + + r_refdefFPM.viewangles[YAW] = FPM_SUB(r_refdefFPM.viewangles[YAW], FPM_FROMFLOAT(lcd_yaw.value)); + for (i=0 ; i<3 ; i++) + r_refdefFPM.vieworg[i] -= FPM_SUB(r_refdefFPM.vieworg[i], FPM_MUL(rightFPM[i],FPM_FROMFLOAT(lcd_x.value))); + R_RenderViewFPM (); + + vid.buffer += vid.rowbytes>>1; + + R_PushDlightsFPM (); + + r_refdefFPM.viewangles[YAW] = FPM_ADD(r_refdefFPM.viewangles[YAW], FPM_MUL(FPM_FROMFLOAT(lcd_yaw.value), FPM_FROMLONG(2))); + for (i=0 ; i<3 ; i++) + r_refdefFPM.vieworg[i] += FPM_MUL(FPM_MUL(FPM_FROMLONG(2), rightFPM[i]), FPM_FROMFLOAT(lcd_x.value)); + R_RenderViewFPM (); + + vid.buffer -= vid.rowbytes>>1; + + r_refdefFPM.vrect.height <<= 1; + + vid.rowbytes >>= 1; + vid.aspect *= 2; + } + else + { + + R_RenderViewFPM (); + + } + + if(crosshair.value){ + Draw_Character ((int)(scr_vrect.x + scr_vrect.width/2), (int)(scr_vrect.y + scr_vrect.height/2 + cl_crossy.value), '+'); + } + +} +#endif //USEFPM + +//Dan East: +void V_Crosshair(void) { + if (Cmd_Argv(1)[0]==0) + //No param passed, so we default to 0 + crosshair.value=0; + else { + if (!strcmp(Cmd_Argv(1), "0")) crosshair.value=0; + else if (!strcmp(Cmd_Argv(1), "1")) crosshair.value=1; + else if (!strcmp(Cmd_Argv(1), "2")) crosshair.value=2; + else if (!strcmp(Cmd_Argv(1), "3")) crosshair.value=3; + else if (!strcmp(Cmd_Argv(1), "4")) crosshair.value=4; + else Con_Print("Unknown argument. Usage: crosshair [0-4]"); + } +} + +//============================================================================ + +/* +============= +V_Init +============= +*/ +void V_Init (void) +{ + Cmd_AddCommand ("v_cshift", V_cshift_f); +#ifndef USEFPM + Cmd_AddCommand ("bf", V_BonusFlash_f); + Cmd_AddCommand ("centerview", V_StartPitchDrift); +#else + Cmd_AddCommand ("bf", V_BonusFlash_FPM_f); + Cmd_AddCommand ("centerview", V_StartPitchDriftFPM); +#endif + //Dan East: + Cmd_AddCommand ("crosshair", V_Crosshair); + + Cvar_RegisterVariable (&lcd_x); + Cvar_RegisterVariable (&lcd_yaw); + + Cvar_RegisterVariable (&v_centermove); + Cvar_RegisterVariable (&v_centerspeed); + + Cvar_RegisterVariable (&v_iyaw_cycle); + Cvar_RegisterVariable (&v_iroll_cycle); + Cvar_RegisterVariable (&v_ipitch_cycle); + Cvar_RegisterVariable (&v_iyaw_level); + Cvar_RegisterVariable (&v_iroll_level); + Cvar_RegisterVariable (&v_ipitch_level); + + Cvar_RegisterVariable (&v_idlescale); + Cvar_RegisterVariable (&crosshair); + Cvar_RegisterVariable (&cl_crossx); + Cvar_RegisterVariable (&cl_crossy); + Cvar_RegisterVariable (&r_viewmodeloffset); + Cvar_RegisterVariable (&gl_cshiftpercent); + + Cvar_RegisterVariable (&scr_ofsx); + Cvar_RegisterVariable (&scr_ofsy); + Cvar_RegisterVariable (&scr_ofsz); + Cvar_RegisterVariable (&cl_rollspeed); + Cvar_RegisterVariable (&cl_rollangle); + Cvar_RegisterVariable (&cl_bob); + Cvar_RegisterVariable (&cl_bobcycle); + Cvar_RegisterVariable (&cl_bobup); + + Cvar_RegisterVariable (&v_kicktime); + Cvar_RegisterVariable (&v_kickroll); + Cvar_RegisterVariable (&v_kickpitch); + + BuildGammaTable (1.0); // no gamma yet + Cvar_RegisterVariable (&v_gamma); + +} + + diff --git a/project/jni/application/quake/source/view.h b/project/jni/application/quake/source/view.h new file mode 100644 index 000000000..e5f85b240 --- /dev/null +++ b/project/jni/application/quake/source/view.h @@ -0,0 +1,36 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// view.h + +extern cvar_t v_gamma; + +extern byte gammatable[256]; // palette is sent through this +extern byte ramps[3][256]; +extern float v_blend[4]; + +extern cvar_t lcd_x; + + +void V_Init (void); +void V_RenderView (void); +void V_RenderViewFPM (void); +float V_CalcRoll (vec3_t angles, vec3_t velocity); +void V_UpdatePalette (void); + diff --git a/project/jni/application/quake/source/wad.c b/project/jni/application/quake/source/wad.c new file mode 100644 index 000000000..a69711b67 --- /dev/null +++ b/project/jni/application/quake/source/wad.c @@ -0,0 +1,159 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// wad.c + +#include "quakedef.h" + +int wad_numlumps; +lumpinfo_t *wad_lumps; +byte *wad_base; + +void SwapPic (qpic_t *pic); + +/* +================== +W_CleanupName + +Lowercases name and pads with spaces and a terminating 0 to the length of +lumpinfo_t->name. +Used so lumpname lookups can proceed rapidly by comparing 4 chars at a time +Space padding is so names can be printed nicely in tables. +Can safely be performed in place. +================== +*/ +void W_CleanupName (char *in, char *out) +{ + int i; + int c; + + for (i=0 ; i<16 ; i++ ) + { + c = in[i]; + if (!c) + break; + + if (c >= 'A' && c <= 'Z') + c += ('a' - 'A'); + out[i] = c; + } + + for ( ; i< 16 ; i++ ) + out[i] = 0; +} + + + +/* +==================== +W_LoadWadFile +==================== +*/ +void W_LoadWadFile (char *filename) +{ + lumpinfo_t *lump_p; + wadinfo_t *header; + unsigned i; + int infotableofs; + + wad_base = COM_LoadHunkFile (filename); + + if (!wad_base) + Sys_Error ("W_LoadWadFile: couldn't load %s", filename); + + header = (wadinfo_t *)wad_base; + + if (header->identification[0] != 'W' + || header->identification[1] != 'A' + || header->identification[2] != 'D' + || header->identification[3] != '2') + Sys_Error ("Wad file %s doesn't have WAD2 id\n",filename); + + wad_numlumps = LittleLong(header->numlumps); + infotableofs = LittleLong(header->infotableofs); + wad_lumps = (lumpinfo_t *)(wad_base + infotableofs); + + for (i=0, lump_p = wad_lumps ; i<(unsigned int)wad_numlumps ; i++,lump_p++) + { + lump_p->filepos = LittleLong(lump_p->filepos); + lump_p->size = LittleLong(lump_p->size); + W_CleanupName (lump_p->name, lump_p->name); + if (lump_p->type == TYP_QPIC) + SwapPic ( (qpic_t *)(wad_base + lump_p->filepos)); + } +} + + +/* +============= +W_GetLumpinfo +============= +*/ +lumpinfo_t *W_GetLumpinfo (char *name) +{ + int i; + lumpinfo_t *lump_p; + char clean[16]; + + W_CleanupName (name, clean); + + for (lump_p=wad_lumps, i=0 ; iname)) + return lump_p; + } + + Sys_Error ("W_GetLumpinfo: %s not found", name); + return NULL; +} + +void *W_GetLumpName (char *name) +{ + lumpinfo_t *lump; + + lump = W_GetLumpinfo (name); + + return (void *)(wad_base + lump->filepos); +} + +void *W_GetLumpNum (int num) +{ + lumpinfo_t *lump; + + if (num < 0 || num > wad_numlumps) + Sys_Error ("W_GetLumpNum: bad number: %i", num); + + lump = wad_lumps + num; + + return (void *)(wad_base + lump->filepos); +} + +/* +============================================================================= + +automatic byte swapping + +============================================================================= +*/ + +void SwapPic (qpic_t *pic) +{ + pic->width = LittleLong(pic->width); + pic->height = LittleLong(pic->height); +} diff --git a/project/jni/application/quake/source/wad.h b/project/jni/application/quake/source/wad.h new file mode 100644 index 000000000..125f5d715 --- /dev/null +++ b/project/jni/application/quake/source/wad.h @@ -0,0 +1,75 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// wad.h + +//=============== +// TYPES +//=============== + +#define CMP_NONE 0 +#define CMP_LZSS 1 + +#define TYP_NONE 0 +#define TYP_LABEL 1 + +#define TYP_LUMPY 64 // 64 + grab command number +#define TYP_PALETTE 64 +#define TYP_QTEX 65 +#define TYP_QPIC 66 +#define TYP_SOUND 67 +#define TYP_MIPTEX 68 + +typedef struct +{ + int width, height; + byte data[4]; // variably sized +} qpic_t; + + + +typedef struct +{ + char identification[4]; // should be WAD2 or 2DAW + int numlumps; + int infotableofs; +} wadinfo_t; + +typedef struct +{ + int filepos; + int disksize; + int size; // uncompressed + char type; + char compression; + char pad1, pad2; + char name[16]; // must be null terminated +} lumpinfo_t; + +extern int wad_numlumps; +extern lumpinfo_t *wad_lumps; +extern byte *wad_base; + +void W_LoadWadFile (char *filename); +void W_CleanupName (char *in, char *out); +lumpinfo_t *W_GetLumpinfo (char *name); +void *W_GetLumpName (char *name); +void *W_GetLumpNum (int num); + +void SwapPic (qpic_t *pic); diff --git a/project/jni/application/quake/source/world.c b/project/jni/application/quake/source/world.c new file mode 100644 index 000000000..bcd1eaef8 --- /dev/null +++ b/project/jni/application/quake/source/world.c @@ -0,0 +1,1727 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// world.c -- world query functions + +#include "quakedef.h" + +/* + +entities never clip against themselves, or their owner + +line of sight checks trace->crosscontent, but bullets don't + +*/ + + +typedef struct +{ + vec3_t boxmins, boxmaxs;// enclose the test object along entire move + float *mins, *maxs; // size of the moving object + vec3_t mins2, maxs2; // size when clipping against mosnters + float *start, *end; + trace_t trace; + int type; + edict_t *passedict; +} moveclip_t; + +#ifdef USEFPM +typedef struct +{ + vec3_FPM_t boxmins, boxmaxs;// enclose the test object along entire move + fixedpoint_t *mins, *maxs; // size of the moving object + vec3_FPM_t mins2, maxs2; // size when clipping against mosnters + fixedpoint_t *start, *end; + trace_FPM_t trace; + int type; + edict_FPM_t *passedict; +} moveclip_FPM_t; +#endif //USEFPM + +int SV_HullPointContents (hull_t *hull, int num, vec3_t p); +#ifdef USEFPM +int SV_HullPointContentsFPM (hull_FPM_t *hull, int num, vec3_FPM_t p); +#endif //USEFPM +/* +=============================================================================== + +HULL BOXES + +=============================================================================== +*/ + + +static hull_t box_hull; +static dclipnode_t box_clipnodes[6]; +static mplane_t box_planes[6]; + +#ifdef USEFPM +static hull_FPM_t box_hullFPM; +static mplane_FPM_t box_planesFPM[6]; +#endif //USEFPM +/* +=================== +SV_InitBoxHull + +Set up the planes and clipnodes so that the six floats of a bounding box +can just be stored out and get a proper hull_t structure. +=================== +*/ +void SV_InitBoxHull (void) +{ + int i; + int side; + + box_hull.clipnodes = box_clipnodes; + box_hull.planes = box_planes; + box_hull.firstclipnode = 0; + box_hull.lastclipnode = 5; + + for (i=0 ; i<6 ; i++) + { + box_clipnodes[i].planenum = i; + + side = i&1; + + box_clipnodes[i].children[side] = CONTENTS_EMPTY; + if (i != 5) + box_clipnodes[i].children[side^1] = i + 1; + else + box_clipnodes[i].children[side^1] = CONTENTS_SOLID; + + box_planes[i].type = i>>1; + box_planes[i].normal[i>>1] = 1; + } + +} + +#ifdef USEFPM +void SV_InitBoxHullFPM (void) +{ + int i; + int side; + + box_hullFPM.clipnodes = box_clipnodes; + box_hullFPM.planes = box_planesFPM; + box_hullFPM.firstclipnode = 0; + box_hullFPM.lastclipnode = 5; + + for (i=0 ; i<6 ; i++) + { + box_clipnodes[i].planenum = i; + + side = i&1; + + box_clipnodes[i].children[side] = CONTENTS_EMPTY; + if (i != 5) + box_clipnodes[i].children[side^1] = i + 1; + else + box_clipnodes[i].children[side^1] = CONTENTS_SOLID; + + box_planesFPM[i].type = i>>1; + box_planesFPM[i].normal[i>>1] = 1; + } + +} +#endif //USEFPM + +/* +=================== +SV_HullForBox + +To keep everything totally uniform, bounding boxes are turned into small +BSP trees instead of being compared directly. +=================== +*/ +hull_t *SV_HullForBox (vec3_t mins, vec3_t maxs) +{ + box_planes[0].dist = maxs[0]; + box_planes[1].dist = mins[0]; + box_planes[2].dist = maxs[1]; + box_planes[3].dist = mins[1]; + box_planes[4].dist = maxs[2]; + box_planes[5].dist = mins[2]; + + return &box_hull; +} + +#ifdef USEFPM +hull_FPM_t *SV_HullForBoxFPM (vec3_FPM_t mins, vec3_FPM_t maxs) +{ + box_planesFPM[0].dist = maxs[0]; + box_planesFPM[1].dist = mins[0]; + box_planesFPM[2].dist = maxs[1]; + box_planesFPM[3].dist = mins[1]; + box_planesFPM[4].dist = maxs[2]; + box_planesFPM[5].dist = mins[2]; + + return &box_hullFPM; +} +#endif //USEFPM + +/* +================ +SV_HullForEntity + +Returns a hull that can be used for testing or clipping an object of mins/maxs +size. +Offset is filled in to contain the adjustment that must be added to the +testing object's origin to get a point to use with the returned hull. +================ +*/ +hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset) +{ + model_t *model; + vec3_t size; + vec3_t hullmins, hullmaxs; + hull_t *hull; + +// decide which clipping hull to use, based on the size + if (ent->v.solid == SOLID_BSP) + { // explicit hulls in the BSP model + if (ent->v.movetype != MOVETYPE_PUSH) + Sys_Error ("SOLID_BSP without MOVETYPE_PUSH"); + + model = sv.models[ (int)ent->v.modelindex ]; + + if (!model || model->type != mod_brush) + Sys_Error ("MOVETYPE_PUSH with a non bsp model"); + + VectorSubtract (maxs, mins, size); + if (size[0] < 3) + hull = &model->hulls[0]; + else if (size[0] <= 32) + hull = &model->hulls[1]; + else + hull = &model->hulls[2]; + +// calculate an offset value to center the origin + VectorSubtract (hull->clip_mins, mins, offset); + VectorAdd (offset, ent->v.origin, offset); + } + else + { // create a temp hull from bounding box sizes + + VectorSubtract (ent->v.mins, maxs, hullmins); + VectorSubtract (ent->v.maxs, mins, hullmaxs); + hull = SV_HullForBox (hullmins, hullmaxs); + + VectorCopy (ent->v.origin, offset); + } + + + return hull; +} + +#ifdef USEFPM +hull_FPM_t *SV_HullForEntityFPM (edict_FPM_t *ent, vec3_FPM_t mins, vec3_FPM_t maxs, vec3_FPM_t offset) +{ + model_FPM_t *model; + vec3_FPM_t size; + vec3_FPM_t hullmins, hullmaxs; + vec3_FPM_t tmp; + hull_FPM_t *hull; + +// decide which clipping hull to use, based on the size + if (ent->v.solid == SOLID_BSP) + { // explicit hulls in the BSP model + if (ent->v.movetype != MOVETYPE_PUSH) + Sys_Error ("SOLID_BSP without MOVETYPE_PUSH"); + + model = svFPM.models[ (int)ent->v.modelindex ]; + + if (!model || model->type != mod_brush) + Sys_Error ("MOVETYPE_PUSH with a non bsp model"); + + VectorSubtractFPM (maxs, mins, size); + if (size[0] < 3) + hull = &model->hulls[0]; + else if (size[0] <= 32) + hull = &model->hulls[1]; + else + hull = &model->hulls[2]; + +// calculate an offset value to center the origin + VectorSubtractFPM (hull->clip_mins, mins, offset); + tmp[0]=FPM_FROMFLOAT(ent->v.origin[0]); + tmp[1]=FPM_FROMFLOAT(ent->v.origin[1]); + tmp[2]=FPM_FROMFLOAT(ent->v.origin[2]); + VectorAddFPM (offset, tmp, offset); + } + else + { // create a temp hull from bounding box sizes + + tmp[0]=FPM_FROMFLOAT(ent->v.mins[0]); + tmp[1]=FPM_FROMFLOAT(ent->v.mins[1]); + tmp[2]=FPM_FROMFLOAT(ent->v.mins[2]); + VectorSubtractFPM (tmp, maxs, hullmins); + tmp[0]=FPM_FROMFLOAT(ent->v.maxs[0]); + tmp[1]=FPM_FROMFLOAT(ent->v.maxs[1]); + tmp[2]=FPM_FROMFLOAT(ent->v.maxs[2]); + VectorSubtractFPM (tmp, mins, hullmaxs); + hull = SV_HullForBoxFPM (hullmins, hullmaxs); + + offset[0]=FPM_FROMFLOAT(ent->v.origin[0]); + offset[1]=FPM_FROMFLOAT(ent->v.origin[1]); + offset[2]=FPM_FROMFLOAT(ent->v.origin[2]); + //VectorCopy (ent->v.origin, offset); + } + + + return hull; +} +#endif //USEFPM + +/* +=============================================================================== + +ENTITY AREA CHECKING + +=============================================================================== +*/ + +typedef struct areanode_s +{ + int axis; // -1 = leaf node + float dist; + struct areanode_s *children[2]; + link_t trigger_edicts; + link_t solid_edicts; +} areanode_t; + +#define AREA_DEPTH 4 +#define AREA_NODES 32 + +static areanode_t sv_areanodes[AREA_NODES]; +static int sv_numareanodes; + +/* +=============== +SV_CreateAreaNode + +=============== +*/ +areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs) +{ + areanode_t *anode; + vec3_t size; + vec3_t mins1, maxs1, mins2, maxs2; + + anode = &sv_areanodes[sv_numareanodes]; + sv_numareanodes++; + + ClearLink (&anode->trigger_edicts); + ClearLink (&anode->solid_edicts); + + if (depth == AREA_DEPTH) + { + anode->axis = -1; + anode->children[0] = anode->children[1] = NULL; + return anode; + } + + VectorSubtract (maxs, mins, size); + if (size[0] > size[1]) + anode->axis = 0; + else + anode->axis = 1; + + anode->dist = (float)(0.5 * (maxs[anode->axis] + mins[anode->axis])); + VectorCopy (mins, mins1); + VectorCopy (mins, mins2); + VectorCopy (maxs, maxs1); + VectorCopy (maxs, maxs2); + + maxs1[anode->axis] = mins2[anode->axis] = anode->dist; + + anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2); + anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1); + + return anode; +} + +#ifdef USEFPM +areanode_t *SV_CreateAreaNodeFPM (int depth, vec3_FPM_t mins, vec3_FPM_t maxs) +{ + areanode_t *anode; + vec3_FPM_t size; + vec3_FPM_t mins1, maxs1, mins2, maxs2; + + anode = &sv_areanodes[sv_numareanodes]; + sv_numareanodes++; + + ClearLink (&anode->trigger_edicts); + ClearLink (&anode->solid_edicts); + + if (depth == AREA_DEPTH) + { + anode->axis = -1; + anode->children[0] = anode->children[1] = NULL; + return anode; + } + + VectorSubtractFPM (maxs, mins, size); + if (size[0] > size[1]) + anode->axis = 0; + else + anode->axis = 1; + + anode->dist = (float)(0.5 * (maxs[anode->axis] + mins[anode->axis])); + VectorCopy (mins, mins1); + VectorCopy (mins, mins2); + VectorCopy (maxs, maxs1); + VectorCopy (maxs, maxs2); + + maxs1[anode->axis] = mins2[anode->axis] = FPM_FROMFLOAT(anode->dist); + + anode->children[0] = SV_CreateAreaNodeFPM (depth+1, mins2, maxs2); + anode->children[1] = SV_CreateAreaNodeFPM (depth+1, mins1, maxs1); + + return anode; +} +#endif //USEFPM + +/* +=============== +SV_ClearWorld + +=============== +*/ +void SV_ClearWorld (void) +{ + SV_InitBoxHull (); + + Q_memset (sv_areanodes, 0, sizeof(sv_areanodes)); + sv_numareanodes = 0; + SV_CreateAreaNode (0, sv.worldmodel->mins, sv.worldmodel->maxs); +} + +#ifdef USEFPM +void SV_ClearWorldFPM (void) +{ + SV_InitBoxHullFPM (); + + Q_memset (sv_areanodes, 0, sizeof(sv_areanodes)); + sv_numareanodes = 0; + SV_CreateAreaNodeFPM (0, svFPM.worldmodel->mins, svFPM.worldmodel->maxs); +} +#endif //USEFPM + +/* +=============== +SV_UnlinkEdict + +=============== +*/ +void SV_UnlinkEdict (edict_t *ent) +{ + if (!ent->area.prev) + return; // not linked in anywhere + RemoveLink (&ent->area); + ent->area.prev = ent->area.next = NULL; +} + +#ifdef USEFPM +void SV_UnlinkEdictFPM (edict_FPM_t *ent) +{ + if (!ent->area.prev) + return; // not linked in anywhere + RemoveLink (&ent->area); + ent->area.prev = ent->area.next = NULL; +} +#endif //USEFPM + +/* +==================== +SV_TouchLinks +==================== +*/ +void SV_TouchLinks ( edict_t *ent, areanode_t *node ) +{ + link_t *l, *next; + edict_t *touch; + int old_self, old_other; + +// touch linked edicts + for (l = node->trigger_edicts.next ; l != &node->trigger_edicts ; l = next) + { + next = l->next; + touch = EDICT_FROM_AREA(l); + if (touch == ent) + continue; + if (!touch->v.touch || touch->v.solid != SOLID_TRIGGER) + continue; + if (ent->v.absmin[0] > touch->v.absmax[0] + || ent->v.absmin[1] > touch->v.absmax[1] + || ent->v.absmin[2] > touch->v.absmax[2] + || ent->v.absmax[0] < touch->v.absmin[0] + || ent->v.absmax[1] < touch->v.absmin[1] + || ent->v.absmax[2] < touch->v.absmin[2] ) + continue; + old_self = pr_global_struct->self; + old_other = pr_global_struct->other; + + pr_global_struct->self = EDICT_TO_PROG(touch); + pr_global_struct->other = EDICT_TO_PROG(ent); + pr_global_struct->time = (float)sv.time; + PR_ExecuteProgram (touch->v.touch); + + pr_global_struct->self = old_self; + pr_global_struct->other = old_other; + } + +// recurse down both sides + if (node->axis == -1) + return; + + if ( ent->v.absmax[node->axis] > node->dist ) + SV_TouchLinks ( ent, node->children[0] ); + if ( ent->v.absmin[node->axis] < node->dist ) + SV_TouchLinks ( ent, node->children[1] ); +} + +#ifdef USEFPM +void SV_TouchLinksFPM ( edict_FPM_t *ent, areanode_t *node ) +{ + link_t *l, *next; + edict_FPM_t *touch; + int old_self, old_other; + +// touch linked edicts + for (l = node->trigger_edicts.next ; l != &node->trigger_edicts ; l = next) + { + next = l->next; + touch = EDICT_FROM_AREAFPM(l); + if (touch == ent) + continue; + if (!touch->v.touch || touch->v.solid != SOLID_TRIGGER) + continue; + if (ent->v.absmin[0] > touch->v.absmax[0] + || ent->v.absmin[1] > touch->v.absmax[1] + || ent->v.absmin[2] > touch->v.absmax[2] + || ent->v.absmax[0] < touch->v.absmin[0] + || ent->v.absmax[1] < touch->v.absmin[1] + || ent->v.absmax[2] < touch->v.absmin[2] ) + continue; + old_self = pr_global_struct->self; + old_other = pr_global_struct->other; + + pr_global_struct->self = EDICT_TO_PROG(touch); + pr_global_struct->other = EDICT_TO_PROG(ent); + pr_global_struct->time = (float)svFPM.time; + PR_ExecuteProgramFPM (touch->v.touch); + + pr_global_struct->self = old_self; + pr_global_struct->other = old_other; + } + +// recurse down both sides + if (node->axis == -1) + return; + + if ( ent->v.absmax[node->axis] > node->dist ) + SV_TouchLinksFPM ( ent, node->children[0] ); + if ( ent->v.absmin[node->axis] < node->dist ) + SV_TouchLinksFPM ( ent, node->children[1] ); +} +#endif //USEFPM + +/* +=============== +SV_FindTouchedLeafs + +=============== +*/ +void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node) +{ + mplane_t *splitplane; + mleaf_t *leaf; + int sides; + int leafnum; + + if (node->contents == CONTENTS_SOLID) + return; + +// add an efrag if the node is a leaf + + if ( node->contents < 0) + { + if (ent->num_leafs == MAX_ENT_LEAFS) + return; + + leaf = (mleaf_t *)node; + leafnum = leaf - sv.worldmodel->leafs - 1; + + ent->leafnums[ent->num_leafs] = leafnum; + ent->num_leafs++; + return; + } + +// NODE_MIXED + + splitplane = node->plane; + sides = BOX_ON_PLANE_SIDE(ent->v.absmin, ent->v.absmax, splitplane); + +// recurse down the contacted sides + if (sides & 1) + SV_FindTouchedLeafs (ent, node->children[0]); + + if (sides & 2) + SV_FindTouchedLeafs (ent, node->children[1]); +} + +#ifdef USEFPM +void SV_FindTouchedLeafsFPM (edict_FPM_t *ent, mnode_FPM_t *node) +{ + mplane_FPM_t *splitplane; + mleaf_FPM_t *leaf; + int sides; + int leafnum; + vec3_FPM_t absmin, absmax; + + if (node->contents == CONTENTS_SOLID) + return; + +// add an efrag if the node is a leaf + + if ( node->contents < 0) + { + if (ent->num_leafs == MAX_ENT_LEAFS) + return; + + leaf = (mleaf_FPM_t *)node; + leafnum = leaf - svFPM.worldmodel->leafs - 1; + + ent->leafnums[ent->num_leafs] = leafnum; + ent->num_leafs++; + return; + } + +// NODE_MIXED + + splitplane = node->plane; + absmin[0]=FPM_FROMFLOAT(ent->v.absmin[0]); + absmin[1]=FPM_FROMFLOAT(ent->v.absmin[1]); + absmin[2]=FPM_FROMFLOAT(ent->v.absmin[2]); + absmax[0]=FPM_FROMFLOAT(ent->v.absmax[0]); + absmax[1]=FPM_FROMFLOAT(ent->v.absmax[1]); + absmax[2]=FPM_FROMFLOAT(ent->v.absmax[2]); + sides = BOX_ON_PLANE_SIDE_FPM(absmin, absmax, splitplane); + +// recurse down the contacted sides + if (sides & 1) + SV_FindTouchedLeafsFPM (ent, node->children[0]); + + if (sides & 2) + SV_FindTouchedLeafsFPM (ent, node->children[1]); +} +#endif //USEFPM + +/* +=============== +SV_LinkEdict + +=============== +*/ +void SV_LinkEdict (edict_t *ent, qboolean touch_triggers) +{ + areanode_t *node; + + if (ent->area.prev) + SV_UnlinkEdict (ent); // unlink from old position + + if (ent == sv.edicts) + return; // don't add the world + + if (ent->free) + return; + +// set the abs box +// #ifdef QUAKE2 + if (ent->v.solid == SOLID_BSP && (ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) ) { // expand for rotation + float max, v; + int i; + + max = DotProduct(ent->v.mins, ent->v.mins); + v = DotProduct(ent->v.maxs, ent->v.maxs); + + if (max < v) + max = v; + + max = sqrt(max); + + for (i=0 ; i<3 ; i++) { + ent->v.absmin[i] = ent->v.origin[i] - max; + ent->v.absmax[i] = ent->v.origin[i] + max; + } + } + else +// #endif + { + VectorAdd (ent->v.origin, ent->v.mins, ent->v.absmin); + VectorAdd (ent->v.origin, ent->v.maxs, ent->v.absmax); + } + +// +// to make items easier to pick up and allow them to be grabbed off +// of shelves, the abs sizes are expanded +// + if ((int)ent->v.flags & FL_ITEM) + { + ent->v.absmin[0] -= 15; + ent->v.absmin[1] -= 15; + ent->v.absmax[0] += 15; + ent->v.absmax[1] += 15; + } + else + { // because movement is clipped an epsilon away from an actual edge, + // we must fully check even when bounding boxes don't quite touch + ent->v.absmin[0] -= 1; + ent->v.absmin[1] -= 1; + ent->v.absmin[2] -= 1; + ent->v.absmax[0] += 1; + ent->v.absmax[1] += 1; + ent->v.absmax[2] += 1; + } + +// link to PVS leafs + ent->num_leafs = 0; + if (ent->v.modelindex) + SV_FindTouchedLeafs (ent, sv.worldmodel->nodes); + + if (ent->v.solid == SOLID_NOT) + return; + +// find the first node that the ent's box crosses + node = sv_areanodes; + while (1) + { + if (node->axis == -1) + break; + if (ent->v.absmin[node->axis] > node->dist) + node = node->children[0]; + else if (ent->v.absmax[node->axis] < node->dist) + node = node->children[1]; + else + break; // crosses the node + } + +// link it in + + if (ent->v.solid == SOLID_TRIGGER) + InsertLinkBefore (&ent->area, &node->trigger_edicts); + else + InsertLinkBefore (&ent->area, &node->solid_edicts); + +// if touch_triggers, touch all entities at this node and decend for more + if (touch_triggers) + SV_TouchLinks ( ent, sv_areanodes ); +} + +#ifdef USEFPM +void SV_LinkEdictFPM (edict_FPM_t *ent, qboolean touch_triggers) +{ + areanode_t *node; + + if (ent->area.prev) + SV_UnlinkEdictFPM (ent); // unlink from old position + + if (ent == svFPM.edicts) + return; // don't add the world + + if (ent->free) + return; + +// set the abs box + +#ifdef QUAKE2 + if (ent->v.solid == SOLID_BSP && + (ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) ) + { // expand for rotation + float max, v; + int i; + + max = 0; + for (i=0 ; i<3 ; i++) + { + v =fabs( ent->v.mins[i]); + if (v > max) + max = v; + v =fabs( ent->v.maxs[i]); + if (v > max) + max = v; + } + for (i=0 ; i<3 ; i++) + { + ent->v.absmin[i] = ent->v.origin[i] - max; + ent->v.absmax[i] = ent->v.origin[i] + max; + } + } + else +#endif + { + VectorAdd (ent->v.origin, ent->v.mins, ent->v.absmin); + VectorAdd (ent->v.origin, ent->v.maxs, ent->v.absmax); + } + +// +// to make items easier to pick up and allow them to be grabbed off +// of shelves, the abs sizes are expanded +// + if ((int)ent->v.flags & FL_ITEM) + { + ent->v.absmin[0] -= 15; + ent->v.absmin[1] -= 15; + ent->v.absmax[0] += 15; + ent->v.absmax[1] += 15; + } + else + { // because movement is clipped an epsilon away from an actual edge, + // we must fully check even when bounding boxes don't quite touch + ent->v.absmin[0] -= 1; + ent->v.absmin[1] -= 1; + ent->v.absmin[2] -= 1; + ent->v.absmax[0] += 1; + ent->v.absmax[1] += 1; + ent->v.absmax[2] += 1; + } + +// link to PVS leafs + ent->num_leafs = 0; + if (ent->v.modelindex) + SV_FindTouchedLeafsFPM (ent, svFPM.worldmodel->nodes); + + if (ent->v.solid == SOLID_NOT) + return; + +// find the first node that the ent's box crosses + node = sv_areanodes; + while (1) + { + if (node->axis == -1) + break; + if (ent->v.absmin[node->axis] > node->dist) + node = node->children[0]; + else if (ent->v.absmax[node->axis] < node->dist) + node = node->children[1]; + else + break; // crosses the node + } + +// link it in + + if (ent->v.solid == SOLID_TRIGGER) + InsertLinkBefore (&ent->area, &node->trigger_edicts); + else + InsertLinkBefore (&ent->area, &node->solid_edicts); + +// if touch_triggers, touch all entities at this node and decend for more + if (touch_triggers) + SV_TouchLinksFPM ( ent, sv_areanodes ); +} +#endif //USEFPM + +/* +=============================================================================== + +POINT TESTING IN HULLS + +=============================================================================== +*/ + +#if !id386 + +/* +================== +SV_HullPointContents + +================== +*/ +int SV_HullPointContents (hull_t *hull, int num, vec3_t p) +{ + float d; + dclipnode_t *node; + mplane_t *plane; + + while (num >= 0) + { + if (num < hull->firstclipnode || num > hull->lastclipnode) + Sys_Error ("SV_HullPointContents: bad node number"); + + node = hull->clipnodes + num; + plane = hull->planes + node->planenum; + + if (plane->type < 3) + d = p[plane->type] - plane->dist; + else + d = DotProduct (plane->normal, p) - plane->dist; + if (d < 0) + num = node->children[1]; + else + num = node->children[0]; + } + + return num; +} + +#ifdef USEFPM +int SV_HullPointContentsFPM (hull_FPM_t *hull, int num, vec3_FPM_t p) +{ + fixedpoint_t d; + dclipnode_t *node; + mplane_FPM_t *plane; + + while (num >= 0) + { + if (num < hull->firstclipnode || num > hull->lastclipnode) + Sys_Error ("SV_HullPointContents: bad node number"); + + node = hull->clipnodes + num; + plane = hull->planes + node->planenum; + + if (plane->type < 3) + d = FPM_SUB(p[plane->type], plane->dist); + else + d = FPM_SUB(DotProductFPM (plane->normal, p), plane->dist); + if (d < 0) + num = node->children[1]; + else + num = node->children[0]; + } + + return num; +} +#endif //USEFPM +#endif // !id386 + + +/* +================== +SV_PointContents + +================== +*/ +int SV_PointContents (vec3_t p) +{ + int cont; + + cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); + if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN) + cont = CONTENTS_WATER; + return cont; +} + +#ifdef USEFPM +int SV_PointContentsFPM (vec3_FPM_t p) +{ + int cont; + + cont = SV_HullPointContentsFPM (&svFPM.worldmodel->hulls[0], 0, p); + if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN) + cont = CONTENTS_WATER; + return cont; +} +#endif //USEFPM + +int SV_TruePointContents (vec3_t p) +{ + return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p); +} + +//=========================================================================== + +/* +============ +SV_TestEntityPosition + +This could be a lot more efficient... +============ +*/ +edict_t *SV_TestEntityPosition (edict_t *ent) +{ + trace_t trace; + + trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, 0, ent); + + if (trace.startsolid) + return sv.edicts; + + return NULL; +} + + +/* +=============================================================================== + +LINE TESTING IN HULLS + +=============================================================================== +*/ + +// 1/32 epsilon to keep floating point happy +#define DIST_EPSILON (0.03125) + +/* +================== +SV_RecursiveHullCheck + +================== +*/ +qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace) +{ + dclipnode_t *node; + mplane_t *plane; + float t1, t2; + float frac; + int i; + vec3_t mid; + int side; + float midf; + +// check for empty + if (num < 0) + { + if (num != CONTENTS_SOLID) + { + trace->allsolid = false; + if (num == CONTENTS_EMPTY) + trace->inopen = true; + else + trace->inwater = true; + } + else + trace->startsolid = true; + return true; // empty + } + + if (num < hull->firstclipnode || num > hull->lastclipnode) + Sys_Error ("SV_RecursiveHullCheck: bad node number"); + +// +// find the point distances +// + node = hull->clipnodes + num; + plane = hull->planes + node->planenum; + + if (plane->type < 3) + { + t1 = p1[plane->type] - plane->dist; + t2 = p2[plane->type] - plane->dist; + } + else + { + t1 = DotProduct (plane->normal, p1) - plane->dist; + t2 = DotProduct (plane->normal, p2) - plane->dist; + } + +#if 1 + if (t1 >= 0 && t2 >= 0) + return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace); + if (t1 < 0 && t2 < 0) + return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace); +#else + if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) ) + return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace); + if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) ) + return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace); +#endif + +// put the crosspoint DIST_EPSILON pixels on the near side + if (t1 < 0) + frac = (float)((t1 + DIST_EPSILON)/(t1-t2)); + else + frac = (float)((t1 - DIST_EPSILON)/(t1-t2)); + if (frac < 0) + frac = 0; + if (frac > 1) + frac = 1; + + midf = p1f + (p2f - p1f)*frac; + for (i=0 ; i<3 ; i++) + mid[i] = p1[i] + frac*(p2[i] - p1[i]); + + side = (t1 < 0); + +// move up to the node + if (!SV_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) ) + return false; + +#ifdef PARANOID + if (SV_HullPointContents (sv_hullmodel, mid, node->children[side]) + == CONTENTS_SOLID) + { + Con_Printf ("mid PointInHullSolid\n"); + return false; + } +#endif + + if (SV_HullPointContents (hull, node->children[side^1], mid) + != CONTENTS_SOLID) +// go past the node + return SV_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace); + + if (trace->allsolid) + return false; // never got out of the solid area + +//================== +// the other side of the node is solid, this is the impact point +//================== + if (!side) + { + VectorCopy (plane->normal, trace->plane.normal); + trace->plane.dist = plane->dist; + } + else + { + VectorSubtract (vec3_origin, plane->normal, trace->plane.normal); + trace->plane.dist = -plane->dist; + } + + while (SV_HullPointContents (hull, hull->firstclipnode, mid) + == CONTENTS_SOLID) + { // shouldn't really happen, but does occasionally + frac -= (float)0.1; + if (frac < 0) + { + trace->fraction = midf; + VectorCopy (mid, trace->endpos); + Con_DPrintf ("backup past 0\n"); + return false; + } + midf = p1f + (p2f - p1f)*frac; + for (i=0 ; i<3 ; i++) + mid[i] = p1[i] + frac*(p2[i] - p1[i]); + } + + trace->fraction = midf; + VectorCopy (mid, trace->endpos); + + return false; +} + +#ifdef USEFPM +qboolean SV_RecursiveHullCheckFPM (hull_FPM_t *hull, int num, fixedpoint_t p1f, fixedpoint_t p2f, vec3_FPM_t p1, vec3_FPM_t p2, trace_FPM_t *trace) +{ + dclipnode_t *node; + mplane_FPM_t *plane; + fixedpoint_t t1, t2; + fixedpoint_t frac; + int i; + vec3_FPM_t mid; + int side; + fixedpoint_t midf; + +// check for empty + if (num < 0) + { + if (num != CONTENTS_SOLID) + { + trace->allsolid = false; + if (num == CONTENTS_EMPTY) + trace->inopen = true; + else + trace->inwater = true; + } + else + trace->startsolid = true; + return true; // empty + } + + if (num < hull->firstclipnode || num > hull->lastclipnode) + Sys_Error ("SV_RecursiveHullCheck: bad node number"); + +// +// find the point distances +// + node = hull->clipnodes + num; + plane = hull->planes + node->planenum; + + if (plane->type < 3) + { + t1 = FPM_SUB(p1[plane->type], plane->dist); + t2 = FPM_SUB(p2[plane->type], plane->dist); + } + else + { + t1 = FPM_SUB(DotProductFPM (plane->normal, p1), plane->dist); + t2 = FPM_SUB(DotProductFPM (plane->normal, p2), plane->dist); + } + +#if 1 + if (t1 >= 0 && t2 >= 0) + return SV_RecursiveHullCheckFPM (hull, node->children[0], p1f, p2f, p1, p2, trace); + if (t1 < 0 && t2 < 0) + return SV_RecursiveHullCheckFPM (hull, node->children[1], p1f, p2f, p1, p2, trace); +#else + if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) ) + return SV_RecursiveHullCheckFPM (hull, node->children[0], p1f, p2f, p1, p2, trace); + if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) ) + return SV_RecursiveHullCheckFPM (hull, node->children[1], p1f, p2f, p1, p2, trace); +#endif + +// put the crosspoint DIST_EPSILON pixels on the near side + if (t1 < 0) + frac = FPM_DIV(FPM_ADD(t1, FPM_FROMFLOATC(DIST_EPSILON)),FPM_SUB(t1,t2)); + else + frac = FPM_DIV(FPM_ADD(t1, FPM_FROMFLOATC(DIST_EPSILON)),FPM_SUB(t1,t2)); + if (frac < 0) + frac = 0; + if (frac > FPM_FROMLONGC(1)) + frac = FPM_FROMLONGC(1); + + midf = FPM_ADD(p1f, FPM_MUL(FPM_SUB(p2f, p1f),frac)); + for (i=0 ; i<3 ; i++) + mid[i] = FPM_ADD(p1[i], FPM_MUL(frac,FPM_SUB(p2[i], p1[i]))); + + side = (t1 < 0); + +// move up to the node + if (!SV_RecursiveHullCheckFPM (hull, node->children[side], p1f, midf, p1, mid, trace) ) + return false; + +#ifdef PARANOID + if (SV_HullPointContentsFPM (sv_hullmodel, mid, node->children[side]) + == CONTENTS_SOLID) + { + Con_Printf ("mid PointInHullSolid\n"); + return false; + } +#endif + + if (SV_HullPointContentsFPM (hull, node->children[side^1], mid) + != CONTENTS_SOLID) +// go past the node + return SV_RecursiveHullCheckFPM (hull, node->children[side^1], midf, p2f, mid, p2, trace); + + if (trace->allsolid) + return false; // never got out of the solid area + +//================== +// the other side of the node is solid, this is the impact point +//================== + if (!side) + { + VectorCopy (plane->normal, trace->plane.normal); + trace->plane.dist = plane->dist; + } + else + { + VectorSubtractFPM (vec3_originFPM, plane->normal, trace->plane.normal); + trace->plane.dist = -plane->dist; + } + + while (SV_HullPointContentsFPM (hull, hull->firstclipnode, mid) + == CONTENTS_SOLID) + { // shouldn't really happen, but does occasionally + frac = FPM_SUB(frac, FPM_FROMFLOATC(0.1)); + if (frac < 0) + { + trace->fraction = midf; + VectorCopy (mid, trace->endpos); + Con_DPrintf ("backup past 0\n"); + return false; + } + midf = FPM_ADD(p1f, FPM_MUL(FPM_SUB(p2f, p1f),frac)); + for (i=0 ; i<3 ; i++) + mid[i] = FPM_ADD(p1[i], FPM_MUL(frac,FPM_SUB(p2[i], p1[i]))); + } + + trace->fraction = midf; + VectorCopy (mid, trace->endpos); + + return false; +} +#endif //USEFPM + +/* +================== +SV_ClipMoveToEntity + +Handles selection or creation of a clipping hull, and offseting (and +eventually rotation) of the end points +================== +*/ +trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end) +{ + trace_t trace; + vec3_t offset; + vec3_t start_l, end_l; + hull_t *hull; + +// fill in a default trace + Q_memset (&trace, 0, sizeof(trace_t)); + trace.fraction = 1; + trace.allsolid = true; + VectorCopy (end, trace.endpos); + +// get the clipping hull + hull = SV_HullForEntity (ent, mins, maxs, offset); + + VectorSubtract (start, offset, start_l); + VectorSubtract (end, offset, end_l); + +#ifdef QUAKE2 + // rotate start and end into the models frame of reference + if (ent->v.solid == SOLID_BSP && + (ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) ) + { + vec3_t a; + vec3_t forward, right, up; + vec3_t temp; + + AngleVectors (ent->v.angles, forward, right, up); + + VectorCopy (start_l, temp); + start_l[0] = DotProduct (temp, forward); + start_l[1] = -DotProduct (temp, right); + start_l[2] = DotProduct (temp, up); + + VectorCopy (end_l, temp); + end_l[0] = DotProduct (temp, forward); + end_l[1] = -DotProduct (temp, right); + end_l[2] = DotProduct (temp, up); + } +#endif + +// trace a line through the apropriate clipping hull + SV_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace); + +#ifdef QUAKE2 + // rotate endpos back to world frame of reference + if (ent->v.solid == SOLID_BSP && + (ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) ) + { + vec3_t a; + vec3_t forward, right, up; + vec3_t temp; + + if (trace.fraction != 1) + { + VectorSubtract (vec3_origin, ent->v.angles, a); + AngleVectors (a, forward, right, up); + + VectorCopy (trace.endpos, temp); + trace.endpos[0] = DotProduct (temp, forward); + trace.endpos[1] = -DotProduct (temp, right); + trace.endpos[2] = DotProduct (temp, up); + + VectorCopy (trace.plane.normal, temp); + trace.plane.normal[0] = DotProduct (temp, forward); + trace.plane.normal[1] = -DotProduct (temp, right); + trace.plane.normal[2] = DotProduct (temp, up); + } + } +#endif + +// fix trace up by the offset + if (trace.fraction != 1) + VectorAdd (trace.endpos, offset, trace.endpos); + +// did we clip the move? + if (trace.fraction < 1 || trace.startsolid ) + trace.ent = ent; + + return trace; +} + +#ifdef USEFPM +trace_FPM_t SV_ClipMoveToEntityFPM (edict_FPM_t *ent, vec3_FPM_t start, vec3_FPM_t mins, vec3_FPM_t maxs, vec3_FPM_t end) +{ + trace_FPM_t trace; + vec3_FPM_t offset; + vec3_FPM_t start_l, end_l; + hull_FPM_t *hull; + +// fill in a default trace + Q_memset (&trace, 0, sizeof(trace_FPM_t)); + trace.fraction = 1; + trace.allsolid = true; + VectorCopy (end, trace.endpos); + +// get the clipping hull + hull = SV_HullForEntityFPM (ent, mins, maxs, offset); + + VectorSubtractFPM (start, offset, start_l); + VectorSubtractFPM (end, offset, end_l); + +#ifdef QUAKE2 + // rotate start and end into the models frame of reference + if (ent->v.solid == SOLID_BSP && + (ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) ) + { + vec3_FPM_t a; + vec3_FPM_t forward, right, up; + vec3_FPM_t temp; + + AngleVectorsFPM (ent->v.angles, forward, right, up); + + VectorCopy (start_l, temp); + start_l[0] = DotProductFPM (temp, forward); + start_l[1] = -DotProductFPM (temp, right); + start_l[2] = DotProductFPM (temp, up); + + VectorCopy (end_l, temp); + end_l[0] = DotProductFPM (temp, forward); + end_l[1] = -DotProductFPM (temp, right); + end_l[2] = DotProductFPM (temp, up); + } +#endif + +// trace a line through the apropriate clipping hull + SV_RecursiveHullCheckFPM (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace); + +#ifdef QUAKE2 + // rotate endpos back to world frame of reference + if (ent->v.solid == SOLID_BSP && + (ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) ) + { + vec3_t a; + vec3_t forward, right, up; + vec3_t temp; + + if (trace.fraction != 1) + { + VectorSubtract (vec3_origin, ent->v.angles, a); + AngleVectors (a, forward, right, up); + + VectorCopy (trace.endpos, temp); + trace.endpos[0] = DotProduct (temp, forward); + trace.endpos[1] = -DotProduct (temp, right); + trace.endpos[2] = DotProduct (temp, up); + + VectorCopy (trace.plane.normal, temp); + trace.plane.normal[0] = DotProduct (temp, forward); + trace.plane.normal[1] = -DotProduct (temp, right); + trace.plane.normal[2] = DotProduct (temp, up); + } + } +#endif + +// fix trace up by the offset + if (trace.fraction != 1) + VectorAddFPM (trace.endpos, offset, trace.endpos); + +// did we clip the move? + if (trace.fraction < 1 || trace.startsolid ) + trace.ent = ent; + + return trace; +} +#endif //USEFPM + +//=========================================================================== + +/* +==================== +SV_ClipToLinks + +Mins and maxs enclose the entire area swept by the move +==================== +*/ +void SV_ClipToLinks ( areanode_t *node, moveclip_t *clip ) +{ + link_t *l, *next; + edict_t *touch; + trace_t trace; + +// touch linked edicts + for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next) + { + next = l->next; + touch = EDICT_FROM_AREA(l); + if (touch->v.solid == SOLID_NOT) + continue; + if (touch == clip->passedict) + continue; + if (touch->v.solid == SOLID_TRIGGER) + Sys_Error ("Trigger in clipping list"); + + if (clip->type == MOVE_NOMONSTERS && touch->v.solid != SOLID_BSP) + continue; + + if (clip->boxmins[0] > touch->v.absmax[0] + || clip->boxmins[1] > touch->v.absmax[1] + || clip->boxmins[2] > touch->v.absmax[2] + || clip->boxmaxs[0] < touch->v.absmin[0] + || clip->boxmaxs[1] < touch->v.absmin[1] + || clip->boxmaxs[2] < touch->v.absmin[2] ) + continue; + + if (clip->passedict && clip->passedict->v.size[0] && !touch->v.size[0]) + continue; // points never interact + + // might intersect, so do an exact clip + if (clip->trace.allsolid) + return; + if (clip->passedict) + { + if (PROG_TO_EDICT(touch->v.owner) == clip->passedict) + continue; // don't clip against own missiles + if (PROG_TO_EDICT(clip->passedict->v.owner) == touch) + continue; // don't clip against owner + } + + if ((int)touch->v.flags & FL_MONSTER) + trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins2, clip->maxs2, clip->end); + else + trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins, clip->maxs, clip->end); + if (trace.allsolid || trace.startsolid || + trace.fraction < clip->trace.fraction) + { + trace.ent = touch; + if (clip->trace.startsolid) + { + clip->trace = trace; + clip->trace.startsolid = true; + } + else + clip->trace = trace; + } + else if (trace.startsolid) + clip->trace.startsolid = true; + } + +// recurse down both sides + if (node->axis == -1) + return; + + if ( clip->boxmaxs[node->axis] > node->dist ) + SV_ClipToLinks ( node->children[0], clip ); + if ( clip->boxmins[node->axis] < node->dist ) + SV_ClipToLinks ( node->children[1], clip ); +} + +#ifdef USEFPM +void SV_ClipToLinksFPM ( areanode_t *node, moveclip_FPM_t *clip ) +{ + link_t *l, *next; + edict_FPM_t *touch; + trace_FPM_t trace; + +// touch linked edicts + for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next) + { + next = l->next; + touch = EDICT_FROM_AREAFPM(l); + if (touch->v.solid == SOLID_NOT) + continue; + if (touch == clip->passedict) + continue; + if (touch->v.solid == SOLID_TRIGGER) + Sys_Error ("Trigger in clipping list"); + + if (clip->type == MOVE_NOMONSTERS && touch->v.solid != SOLID_BSP) + continue; + + if (clip->boxmins[0] > touch->v.absmax[0] + || clip->boxmins[1] > touch->v.absmax[1] + || clip->boxmins[2] > touch->v.absmax[2] + || clip->boxmaxs[0] < touch->v.absmin[0] + || clip->boxmaxs[1] < touch->v.absmin[1] + || clip->boxmaxs[2] < touch->v.absmin[2] ) + continue; + + if (clip->passedict && clip->passedict->v.size[0] && !touch->v.size[0]) + continue; // points never interact + + // might intersect, so do an exact clip + if (clip->trace.allsolid) + return; + if (clip->passedict) + { + if (PROG_TO_EDICTFPM(touch->v.owner) == clip->passedict) + continue; // don't clip against own missiles + if (PROG_TO_EDICTFPM(clip->passedict->v.owner) == touch) + continue; // don't clip against owner + } + + if ((int)touch->v.flags & FL_MONSTER) + trace = SV_ClipMoveToEntityFPM (touch, clip->start, clip->mins2, clip->maxs2, clip->end); + else + trace = SV_ClipMoveToEntityFPM (touch, clip->start, clip->mins, clip->maxs, clip->end); + if (trace.allsolid || trace.startsolid || + trace.fraction < clip->trace.fraction) + { + trace.ent = touch; + if (clip->trace.startsolid) + { + clip->trace = trace; + clip->trace.startsolid = true; + } + else + clip->trace = trace; + } + else if (trace.startsolid) + clip->trace.startsolid = true; + } + +// recurse down both sides + if (node->axis == -1) + return; + + if ( clip->boxmaxs[node->axis] > node->dist ) + SV_ClipToLinksFPM ( node->children[0], clip ); + if ( clip->boxmins[node->axis] < node->dist ) + SV_ClipToLinksFPM ( node->children[1], clip ); +} +#endif //USEFPM + +/* +================== +SV_MoveBounds +================== +*/ +void SV_MoveBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs) +{ +#if 0 +// debug to test against everything +boxmins[0] = boxmins[1] = boxmins[2] = -9999; +boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999; +#else + int i; + + for (i=0 ; i<3 ; i++) + { + if (end[i] > start[i]) + { + boxmins[i] = start[i] + mins[i] - 1; + boxmaxs[i] = end[i] + maxs[i] + 1; + } + else + { + boxmins[i] = end[i] + mins[i] - 1; + boxmaxs[i] = start[i] + maxs[i] + 1; + } + } +#endif +} + +#ifdef USEFPM +void SV_MoveBoundsFPM (vec3_FPM_t start, vec3_FPM_t mins, vec3_FPM_t maxs, vec3_FPM_t end, vec3_FPM_t boxmins, vec3_FPM_t boxmaxs) +{ +#if 0 +// debug to test against everything +boxmins[0] = boxmins[1] = boxmins[2] = -9999; +boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999; +#else + int i; + + for (i=0 ; i<3 ; i++) + { + if (end[i] > start[i]) + { + boxmins[i] = FPM_SUB(FPM_ADD(start[i], mins[i]), FPM_FROMLONGC(1)); + boxmaxs[i] = FPM_ADD3(end[i], maxs[i], FPM_FROMLONGC(1)); + } + else + { + boxmins[i] = FPM_SUB(FPM_ADD(end[i], mins[i]), FPM_FROMLONGC(1)); + boxmaxs[i] = FPM_ADD3(start[i], maxs[i], FPM_FROMLONGC(1)); + } + } +#endif +} +#endif //USEFPM + +/* +================== +SV_Move +================== +*/ +trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict) +{ + moveclip_t clip; + int i; + + Q_memset ( &clip, 0, sizeof ( moveclip_t ) ); + +// clip to world + clip.trace = SV_ClipMoveToEntity ( sv.edicts, start, mins, maxs, end ); + + clip.start = start; + clip.end = end; + clip.mins = mins; + clip.maxs = maxs; + clip.type = type; + clip.passedict = passedict; + + if (type == MOVE_MISSILE) + { + for (i=0 ; i<3 ; i++) + { + clip.mins2[i] = -15; + clip.maxs2[i] = 15; + } + } + else + { + VectorCopy (mins, clip.mins2); + VectorCopy (maxs, clip.maxs2); + } + +// create the bounding box of the entire move + SV_MoveBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs ); + +// clip to entities + SV_ClipToLinks ( sv_areanodes, &clip ); + + return clip.trace; +} + +#ifdef USEFPM +trace_FPM_t SV_MoveFPM (vec3_FPM_t start, vec3_FPM_t mins, vec3_FPM_t maxs, vec3_FPM_t end, int type, edict_FPM_t *passedict) +{ + moveclip_FPM_t clip; + int i; + + Q_memset ( &clip, 0, sizeof ( moveclip_FPM_t ) ); + +// clip to world + clip.trace = SV_ClipMoveToEntityFPM ( svFPM.edicts, start, mins, maxs, end ); + + clip.start = start; + clip.end = end; + clip.mins = mins; + clip.maxs = maxs; + clip.type = type; + clip.passedict = passedict; + + if (type == MOVE_MISSILE) + { + for (i=0 ; i<3 ; i++) + { + clip.mins2[i] = -15; + clip.maxs2[i] = 15; + } + } + else + { + VectorCopy (mins, clip.mins2); + VectorCopy (maxs, clip.maxs2); + } + +// create the bounding box of the entire move + SV_MoveBoundsFPM ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs ); + +// clip to entities + SV_ClipToLinksFPM ( sv_areanodes, &clip ); + + return clip.trace; +} +#endif //USEFPM diff --git a/project/jni/application/quake/source/world.h b/project/jni/application/quake/source/world.h new file mode 100644 index 000000000..50b85ea4d --- /dev/null +++ b/project/jni/application/quake/source/world.h @@ -0,0 +1,101 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// world.h + +typedef struct +{ + vec3_t normal; + float dist; +} plane_t; + +typedef struct +{ + vec3_FPM_t normal; + fixedpoint_t dist; +} plane_FPM_t; + +typedef struct +{ + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area + qboolean inopen, inwater; + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + plane_t plane; // surface normal at impact + edict_t *ent; // entity the surface is on +} trace_t; + +typedef struct +{ + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area + qboolean inopen, inwater; + fixedpoint_t fraction; // time completed, 1.0 = didn't hit anything + vec3_FPM_t endpos; // final position + plane_FPM_t plane; // surface normal at impact + edict_FPM_t *ent; // entity the surface is on +} trace_FPM_t; + + +#define MOVE_NORMAL 0 +#define MOVE_NOMONSTERS 1 +#define MOVE_MISSILE 2 + + +void SV_ClearWorld (void); +void SV_ClearWorldFPM (void); +// called after the world model has been loaded, before linking any entities + +void SV_UnlinkEdict (edict_t *ent); +void SV_UnlinkEdictFPM (edict_FPM_t *ent); +// call before removing an entity, and before trying to move one, +// so it doesn't clip against itself +// flags ent->v.modified + +void SV_LinkEdict (edict_t *ent, qboolean touch_triggers); +void SV_LinkEdictFPM (edict_FPM_t *ent, qboolean touch_triggers); +// Needs to be called any time an entity changes origin, mins, maxs, or solid +// flags ent->v.modified +// sets ent->v.absmin and ent->v.absmax +// if touchtriggers, calls prog functions for the intersected triggers + +int SV_PointContents (vec3_t p); +int SV_PointContentsFPM (vec3_FPM_t p); +int SV_TruePointContents (vec3_t p); +// returns the CONTENTS_* value from the world at the given point. +// does not check any entities at all +// the non-true version remaps the water current contents to content_water + +edict_t *SV_TestEntityPosition (edict_t *ent); + +trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict); +trace_FPM_t SV_MoveFPM (vec3_FPM_t start, vec3_FPM_t mins, vec3_FPM_t maxs, vec3_FPM_t end, int type, edict_FPM_t *passedict); + +// mins and maxs are reletive + +// if the entire move stays in a solid volume, trace.allsolid will be set + +// if the starting point is in a solid, it will be allowed to move out +// to an open area + +// nomonsters is used for line of sight or edge testing, where mosnters +// shouldn't be considered solid objects + +// passedict is explicitly excluded from clipping checks (normally NULL) diff --git a/project/jni/application/quake/source/zone.c b/project/jni/application/quake/source/zone.c new file mode 100644 index 000000000..ee6d02075 --- /dev/null +++ b/project/jni/application/quake/source/zone.c @@ -0,0 +1,939 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Z_zone.c + +#include "quakedef.h" + +#define DYNAMIC_SIZE 0xc000 + +#define ZONEID 0x1d4a11 +#define MINFRAGMENT 64 + +typedef struct memblock_s +{ + int size; // including the header and possibly tiny fragments + int tag; // a tag of 0 is a free block + int id; // should be ZONEID + struct memblock_s *next, *prev; + int pad; // pad to 64 bit boundary +} memblock_t; + +typedef struct +{ + int size; // total bytes malloced, including header + memblock_t blocklist; // start / end cap for linked list + memblock_t *rover; +} memzone_t; + +void Cache_FreeLow (int new_low_hunk); +void Cache_FreeHigh (int new_high_hunk); + + +/* +============================================================================== + + ZONE MEMORY ALLOCATION + +There is never any space between memblocks, and there will never be two +contiguous free memblocks. + +The rover can be left pointing at a non-empty block + +The zone calls are pretty much only used for small strings and structures, +all big things are allocated on the hunk. +============================================================================== +*/ + +memzone_t *mainzone; + +void Z_ClearZone (memzone_t *zone, int size); + + +/* +======================== +Z_ClearZone +======================== +*/ +void Z_ClearZone (memzone_t *zone, int size) +{ + memblock_t *block; + +// set the entire zone to one free block + + zone->blocklist.next = zone->blocklist.prev = block = + (memblock_t *)( (byte *)zone + sizeof(memzone_t) ); + zone->blocklist.tag = 1; // in use block + zone->blocklist.id = 0; + zone->blocklist.size = 0; + zone->rover = block; + + block->prev = block->next = &zone->blocklist; + block->tag = 0; // free block + block->id = ZONEID; + block->size = size - sizeof(memzone_t); +} + + +/* +======================== +Z_Free +======================== +*/ +void Z_Free (void *ptr) +{ + memblock_t *block, *other; + + if (!ptr) + Sys_Error ("Z_Free: NULL pointer"); + + block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t)); + if (block->id != ZONEID) + Sys_Error ("Z_Free: freed a pointer without ZONEID"); + if (block->tag == 0) + Sys_Error ("Z_Free: freed a freed pointer"); + + block->tag = 0; // mark as free + + other = block->prev; + if (!other->tag) + { // merge with previous free block + other->size += block->size; + other->next = block->next; + other->next->prev = other; + if (block == mainzone->rover) + mainzone->rover = other; + block = other; + } + + other = block->next; + if (!other->tag) + { // merge the next free block onto the end + block->size += other->size; + block->next = other->next; + block->next->prev = block; + if (other == mainzone->rover) + mainzone->rover = block; + } +} + + +/* +======================== +Z_Malloc +======================== +*/ +void *Z_Malloc (int size) +{ + void *buf; + + Z_CheckHeap (); // DEBUG + buf = Z_TagMalloc (size, 1); + if (!buf) + Sys_Error ("Z_Malloc: failed on allocation of %i bytes",size); + Q_memset (buf, 0, size); + + return buf; +} + +void *Z_TagMalloc (int size, int tag) +{ + int extra; + memblock_t *start, *rover, *new, *base; + + if (!tag) + Sys_Error ("Z_TagMalloc: tried to use a 0 tag"); + +// +// scan through the block list looking for the first free block +// of sufficient size +// + size += sizeof(memblock_t); // account for size of block header + size += 4; // space for memory trash tester + size = (size + 7) & ~7; // align to 8-byte boundary + + base = rover = mainzone->rover; + start = base->prev; + + do + { + if (rover == start) // scaned all the way around the list + return NULL; + if (rover->tag) + base = rover = rover->next; + else + rover = rover->next; + } while (base->tag || base->size < size); + +// +// found a block big enough +// + extra = base->size - size; + if (extra > MINFRAGMENT) + { // there will be a free fragment after the allocated block + new = (memblock_t *) ((byte *)base + size ); + new->size = extra; + new->tag = 0; // free block + new->prev = base; + new->id = ZONEID; + new->next = base->next; + new->next->prev = new; + base->next = new; + base->size = size; + } + + base->tag = tag; // no longer a free block + + mainzone->rover = base->next; // next allocation will start looking here + + base->id = ZONEID; + +// marker for memory trash testing + *(int *)((byte *)base + base->size - 4) = ZONEID; + + return (void *) ((byte *)base + sizeof(memblock_t)); +} + + +/* +======================== +Z_Print +======================== +*/ +void Z_Print (memzone_t *zone) +{ + memblock_t *block; + + Con_Printf ("zone size: %i location: %p\n",mainzone->size,mainzone); + + for (block = zone->blocklist.next ; ; block = block->next) + { + Con_Printf ("block:%p size:%7i tag:%3i\n", + block, block->size, block->tag); + + if (block->next == &zone->blocklist) + break; // all blocks have been hit + if ( (byte *)block + block->size != (byte *)block->next) + Con_Printf ("ERROR: block size does not touch the next block\n"); + if ( block->next->prev != block) + Con_Printf ("ERROR: next block doesn't have proper back link\n"); + if (!block->tag && !block->next->tag) + Con_Printf ("ERROR: two consecutive free blocks\n"); + } +} + + +/* +======================== +Z_CheckHeap +======================== +*/ +void Z_CheckHeap (void) +{ + memblock_t *block; + + for (block = mainzone->blocklist.next ; ; block = block->next) + { + if (block->next == &mainzone->blocklist) + break; // all blocks have been hit + if ( (byte *)block + block->size != (byte *)block->next) + Sys_Error ("Z_CheckHeap: block size does not touch the next block\n"); + if ( block->next->prev != block) + Sys_Error ("Z_CheckHeap: next block doesn't have proper back link\n"); + if (!block->tag && !block->next->tag) + Sys_Error ("Z_CheckHeap: two consecutive free blocks\n"); + } +} + +//============================================================================ + +#define HUNK_SENTINAL 0x1df001ed + +typedef struct +{ + int sentinal; + int size; // including sizeof(hunk_t), -1 = not allocated + char name[8]; +} hunk_t; + +byte *hunk_base; +int hunk_size; + +int hunk_low_used; +int hunk_high_used; + +qboolean hunk_tempactive; +int hunk_tempmark; + +void R_FreeTextures (void); + +/* +============== +Hunk_Check + +Run consistancy and sentinal trahing checks +============== +*/ +void Hunk_Check (void) +{ + hunk_t *h; + + for (h = (hunk_t *)hunk_base ; (byte *)h != hunk_base + hunk_low_used ; ) + { + if (h->sentinal != HUNK_SENTINAL) + Sys_Error ("Hunk_Check: trahsed sentinal"); + if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size) + Sys_Error ("Hunk_Check: bad size"); + h = (hunk_t *)((byte *)h+h->size); + } +} + +/* +============== +Hunk_Print + +If "all" is specified, every single allocation is printed. +Otherwise, allocations with the same name will be totaled up before printing. +============== +*/ +void Hunk_Print (qboolean all) +{ + hunk_t *h, *next, *endlow, *starthigh, *endhigh; + int count, sum; + int totalblocks; + char name[9]; + + name[8] = 0; + count = 0; + sum = 0; + totalblocks = 0; + + h = (hunk_t *)hunk_base; + endlow = (hunk_t *)(hunk_base + hunk_low_used); + starthigh = (hunk_t *)(hunk_base + hunk_size - hunk_high_used); + endhigh = (hunk_t *)(hunk_base + hunk_size); + + Con_Printf (" :%8i total hunk size\n", hunk_size); + Con_Printf ("-------------------------\n"); + + while (1) + { + // + // skip to the high hunk if done with low hunk + // + if ( h == endlow ) + { + Con_Printf ("-------------------------\n"); + Con_Printf (" :%8i REMAINING\n", hunk_size - hunk_low_used - hunk_high_used); + Con_Printf ("-------------------------\n"); + h = starthigh; + } + + // + // if totally done, break + // + if ( h == endhigh ) + break; + + // + // run consistancy checks + // + if (h->sentinal != HUNK_SENTINAL) + Sys_Error ("Hunk_Check: trahsed sentinal"); + if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size) + Sys_Error ("Hunk_Check: bad size"); + + next = (hunk_t *)((byte *)h+h->size); + count++; + totalblocks++; + sum += h->size; + + // + // print the single block + // + Q_memcpy (name, h->name, 8); + if (all) + Con_Printf ("%8p :%8i %8s\n",h, h->size, name); + + // + // print the total + // + if (next == endlow || next == endhigh || + strncmp (h->name, next->name, 8) ) + { + if (!all) + Con_Printf (" :%8i %8s (TOTAL)\n",sum, name); + count = 0; + sum = 0; + } + + h = next; + } + + Con_Printf ("-------------------------\n"); + Con_Printf ("%8i total blocks\n", totalblocks); + +} + +/* +=================== +Hunk_AllocName +=================== +*/ +void *Hunk_AllocName (int size, char *name) +{ + hunk_t *h; + +#ifdef PARANOID + Hunk_Check (); +#endif + + if (size < 0) + Sys_Error ("Hunk_Alloc: bad size: %i", size); + + size = sizeof(hunk_t) + ((size+15)&~15); + + if (hunk_size - hunk_low_used - hunk_high_used < size) + Sys_Error ("Hunk_Alloc: failed on %i bytes",size); + + h = (hunk_t *)(hunk_base + hunk_low_used); + hunk_low_used += size; + + Cache_FreeLow (hunk_low_used); + + Q_memset (h, 0, size); + + h->size = size; + h->sentinal = HUNK_SENTINAL; + Q_strncpy (h->name, name, 8); + + return (void *)(h+1); +} + +/* +=================== +Hunk_Alloc +=================== +*/ +void *Hunk_Alloc (int size) +{ + return Hunk_AllocName (size, "unknown"); +} + +int Hunk_LowMark (void) +{ + return hunk_low_used; +} + +void Hunk_FreeToLowMark (int mark) +{ + if (mark < 0 || mark > hunk_low_used) + Sys_Error ("Hunk_FreeToLowMark: bad mark %i", mark); + Q_memset (hunk_base + mark, 0, hunk_low_used - mark); + hunk_low_used = mark; +} + +int Hunk_HighMark (void) +{ + if (hunk_tempactive) + { + hunk_tempactive = false; + Hunk_FreeToHighMark (hunk_tempmark); + } + + return hunk_high_used; +} + +void Hunk_FreeToHighMark (int mark) +{ + if (hunk_tempactive) + { + hunk_tempactive = false; + Hunk_FreeToHighMark (hunk_tempmark); + } + if (mark < 0 || mark > hunk_high_used) + Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark); + Q_memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark); + hunk_high_used = mark; +} + + +/* +=================== +Hunk_HighAllocName +=================== +*/ +void *Hunk_HighAllocName (int size, char *name) +{ + hunk_t *h; + + if (size < 0) + Sys_Error ("Hunk_HighAllocName: bad size: %i", size); + + if (hunk_tempactive) + { + Hunk_FreeToHighMark (hunk_tempmark); + hunk_tempactive = false; + } + +#ifdef PARANOID + Hunk_Check (); +#endif + + size = sizeof(hunk_t) + ((size+15)&~15); + + if (hunk_size - hunk_low_used - hunk_high_used < size) + { + Con_Printf ("Hunk_HighAlloc: failed on %i bytes\n",size); + return NULL; + } + + hunk_high_used += size; + Cache_FreeHigh (hunk_high_used); + + h = (hunk_t *)(hunk_base + hunk_size - hunk_high_used); + + Q_memset (h, 0, size); + h->size = size; + h->sentinal = HUNK_SENTINAL; + Q_strncpy (h->name, name, 8); + + return (void *)(h+1); +} + + +/* +================= +Hunk_TempAlloc + +Return space from the top of the hunk +================= +*/ +void *Hunk_TempAlloc (int size) +{ + void *buf; + + size = (size+15)&~15; + + if (hunk_tempactive) + { + Hunk_FreeToHighMark (hunk_tempmark); + hunk_tempactive = false; + } + + hunk_tempmark = Hunk_HighMark (); + + buf = Hunk_HighAllocName (size, "temp"); + + hunk_tempactive = true; + + return buf; +} + +/* +=============================================================================== + +CACHE MEMORY + +=============================================================================== +*/ + +typedef struct cache_system_s +{ + int size; // including this header + cache_user_t *user; + char name[16]; + struct cache_system_s *prev, *next; + struct cache_system_s *lru_prev, *lru_next; // for LRU flushing +} cache_system_t; + +cache_system_t *Cache_TryAlloc (int size, qboolean nobottom); + +cache_system_t cache_head; + +/* +=========== +Cache_Move +=========== +*/ +void Cache_Move ( cache_system_t *c) +{ + cache_system_t *new; + +// we are clearing up space at the bottom, so only allocate it late + new = Cache_TryAlloc (c->size, true); + if (new) + { +// Con_Printf ("cache_move ok\n"); + + Q_memcpy ( new+1, c+1, c->size - sizeof(cache_system_t) ); + new->user = c->user; + Q_memcpy (new->name, c->name, sizeof(new->name)); + Cache_Free (c->user); + new->user->data = (void *)(new+1); + } + else + { +// Con_Printf ("cache_move failed\n"); + + Cache_Free (c->user); // tough luck... + } +} + +/* +============ +Cache_FreeLow + +Throw things out until the hunk can be expanded to the given point +============ +*/ +void Cache_FreeLow (int new_low_hunk) +{ + cache_system_t *c; + + while (1) + { + c = cache_head.next; + if (c == &cache_head) + return; // nothing in cache at all + if ((byte *)c >= hunk_base + new_low_hunk) + return; // there is space to grow the hunk + Cache_Move ( c ); // reclaim the space + } +} + +/* +============ +Cache_FreeHigh + +Throw things out until the hunk can be expanded to the given point +============ +*/ +void Cache_FreeHigh (int new_high_hunk) +{ + cache_system_t *c, *prev; + + prev = NULL; + while (1) + { + c = cache_head.prev; + if (c == &cache_head) + return; // nothing in cache at all + if ( (byte *)c + c->size <= hunk_base + hunk_size - new_high_hunk) + return; // there is space to grow the hunk + if (c == prev) + Cache_Free (c->user); // didn't move out of the way + else + { + Cache_Move (c); // try to move it + prev = c; + } + } +} + +void Cache_UnlinkLRU (cache_system_t *cs) +{ + if (!cs->lru_next || !cs->lru_prev) + Sys_Error ("Cache_UnlinkLRU: NULL link"); + + cs->lru_next->lru_prev = cs->lru_prev; + cs->lru_prev->lru_next = cs->lru_next; + + cs->lru_prev = cs->lru_next = NULL; +} + +void Cache_MakeLRU (cache_system_t *cs) +{ + if (cs->lru_next || cs->lru_prev) + Sys_Error ("Cache_MakeLRU: active link"); + + cache_head.lru_next->lru_prev = cs; + cs->lru_next = cache_head.lru_next; + cs->lru_prev = &cache_head; + cache_head.lru_next = cs; +} + +/* +============ +Cache_TryAlloc + +Looks for a free block of memory between the high and low hunk marks +Size should already include the header and padding +============ +*/ +cache_system_t *Cache_TryAlloc (int size, qboolean nobottom) +{ + cache_system_t *cs, *new; + +// is the cache completely empty? + + if (!nobottom && cache_head.prev == &cache_head) + { + if (hunk_size - hunk_high_used - hunk_low_used < size) + Sys_Error ("Cache_TryAlloc: %i is greater then free hunk", size); + + new = (cache_system_t *) (hunk_base + hunk_low_used); + Q_memset (new, 0, sizeof(*new)); + new->size = size; + + cache_head.prev = cache_head.next = new; + new->prev = new->next = &cache_head; + + Cache_MakeLRU (new); + return new; + } + +// search from the bottom up for space + + new = (cache_system_t *) (hunk_base + hunk_low_used); + cs = cache_head.next; + + do + { + if (!nobottom || cs != cache_head.next) + { + if ( (byte *)cs - (byte *)new >= size) + { // found space + Q_memset (new, 0, sizeof(*new)); + new->size = size; + + new->next = cs; + new->prev = cs->prev; + cs->prev->next = new; + cs->prev = new; + + Cache_MakeLRU (new); + + return new; + } + } + + // continue looking + new = (cache_system_t *)((byte *)cs + cs->size); + cs = cs->next; + + } while (cs != &cache_head); + +// try to allocate one at the very end + if ( hunk_base + hunk_size - hunk_high_used - (byte *)new >= size) + { + Q_memset (new, 0, sizeof(*new)); + new->size = size; + + new->next = &cache_head; + new->prev = cache_head.prev; + cache_head.prev->next = new; + cache_head.prev = new; + + Cache_MakeLRU (new); + + return new; + } + + return NULL; // couldn't allocate +} + +/* +============ +Cache_Flush + +Throw everything out, so new data will be demand cached +============ +*/ +void Cache_Flush (void) +{ + while (cache_head.next != &cache_head) + Cache_Free ( cache_head.next->user ); // reclaim the space +} + + +/* +============ +Cache_Print + +============ +*/ +void Cache_Print (void) +{ + cache_system_t *cd; + + for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next) + { + Con_Printf ("%8i : %s\n", cd->size, cd->name); + } +} + +/* +============ +Cache_Report + +============ +*/ +void Cache_Report (void) +{ + Con_DPrintf ("%4.1f megabyte data cache\n", (hunk_size - hunk_high_used - hunk_low_used) / (float)(1024*1024) ); +} + +/* +============ +Cache_Compact + +============ +*/ +void Cache_Compact (void) +{ +} + +/* +============ +Cache_Init + +============ +*/ +void Cache_Init (void) +{ + cache_head.next = cache_head.prev = &cache_head; + cache_head.lru_next = cache_head.lru_prev = &cache_head; + + Cmd_AddCommand ("flush", Cache_Flush); +} + +/* +============== +Cache_Free + +Frees the memory and removes it from the LRU list +============== +*/ +void Cache_Free (cache_user_t *c) +{ + cache_system_t *cs; + + if (!c->data) + Sys_Error ("Cache_Free: not allocated"); + + cs = ((cache_system_t *)c->data) - 1; + + cs->prev->next = cs->next; + cs->next->prev = cs->prev; + cs->next = cs->prev = NULL; + + c->data = NULL; + + Cache_UnlinkLRU (cs); +} + + + +/* +============== +Cache_Check +============== +*/ +void *Cache_Check (cache_user_t *c) +{ + cache_system_t *cs; + + if (!c->data) + return NULL; + + cs = ((cache_system_t *)c->data) - 1; + +// move to head of LRU + Cache_UnlinkLRU (cs); + Cache_MakeLRU (cs); + + return c->data; +} + + +/* +============== +Cache_Alloc +============== +*/ +void *Cache_Alloc (cache_user_t *c, int size, char *name) +{ + cache_system_t *cs; + + if (c->data) + Sys_Error ("Cache_Alloc: allready allocated"); + + if (size <= 0) + Sys_Error ("Cache_Alloc: size %i", size); + + size = (size + sizeof(cache_system_t) + 15) & ~15; + +// find memory for it + while (1) + { + cs = Cache_TryAlloc (size, false); + if (cs) + { + strncpy (cs->name, name, sizeof(cs->name)-1); + c->data = (void *)(cs+1); + cs->user = c; + break; + } + + // free the least recently used cahedat + if (cache_head.lru_prev == &cache_head) + Sys_Error ("Cache_Alloc: out of memory"); + // not enough memory at all + Cache_Free ( cache_head.lru_prev->user ); + } + + return Cache_Check (c); +} + +//============================================================================ + + +/* +======================== +Memory_Init +======================== +*/ +void Memory_Init (void *buf, int size) +{ + int p; + int zonesize = DYNAMIC_SIZE; + + + hunk_base = buf; + hunk_size = size; + hunk_low_used = 0; + hunk_high_used = 0; + + Cache_Init (); + p = COM_CheckParm ("-zone"); + if (p) + { + if (p < com_argc-1) + zonesize = Q_atoi (com_argv[p+1]) * 1024; + else + Sys_Error ("Memory_Init: you must specify a size in KB after -zone"); + } + + mainzone = Hunk_AllocName (zonesize, "zone" ); + + Z_ClearZone (mainzone, zonesize); + +} + diff --git a/project/jni/application/quake/source/zone.h b/project/jni/application/quake/source/zone.h new file mode 100644 index 000000000..b63006f8d --- /dev/null +++ b/project/jni/application/quake/source/zone.h @@ -0,0 +1,131 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/* + memory allocation + + +H_??? The hunk manages the entire memory block given to quake. It must be +contiguous. Memory can be allocated from either the low or high end in a +stack fashion. The only way memory is released is by resetting one of the +pointers. + +Hunk allocations should be given a name, so the Hunk_Print () function +can display usage. + +Hunk allocations are guaranteed to be 16 byte aligned. + +The video buffers are allocated high to avoid leaving a hole underneath +server allocations when changing to a higher video mode. + + +Z_??? Zone memory functions used for small, dynamic allocations like text +strings from command input. There is only about 48K for it, allocated at +the very bottom of the hunk. + +Cache_??? Cache memory is for objects that can be dynamically loaded and +can usefully stay persistant between levels. The size of the cache +fluctuates from level to level. + +To allocate a cachable object + + +Temp_??? Temp memory is used for file loading and surface caching. The size +of the cache memory is adjusted so that there is a minimum of 512k remaining +for temp memory. + + +------ Top of Memory ------- + +high hunk allocations + +<--- high hunk reset point held by vid + +video buffer + +z buffer + +surface cache + +<--- high hunk used + +cachable memory + +<--- low hunk used + +client and server low hunk allocations + +<-- low hunk reset point held by host + +startup hunk allocations + +Zone block + +----- Bottom of Memory ----- + + + +*/ + +void Memory_Init (void *buf, int size); + +void Z_Free (void *ptr); +void *Z_Malloc (int size); // returns 0 filled memory +void *Z_TagMalloc (int size, int tag); + +void Z_DumpHeap (void); +void Z_CheckHeap (void); +int Z_FreeMemory (void); + +void *Hunk_Alloc (int size); // returns 0 filled memory +void *Hunk_AllocName (int size, char *name); + +void *Hunk_HighAllocName (int size, char *name); + +int Hunk_LowMark (void); +void Hunk_FreeToLowMark (int mark); + +int Hunk_HighMark (void); +void Hunk_FreeToHighMark (int mark); + +void *Hunk_TempAlloc (int size); + +void Hunk_Check (void); + +typedef struct cache_user_s +{ + void *data; +} cache_user_t; + +void Cache_Flush (void); + +void *Cache_Check (cache_user_t *c); +// returns the cached data, and moves to the head of the LRU list +// if present, otherwise returns NULL + +void Cache_Free (cache_user_t *c); + +void *Cache_Alloc (cache_user_t *c, int size, char *name); +// Returns NULL if all purgable data was tossed and there still +// wasn't enough room. + +void Cache_Report (void); + + + diff --git a/project/jni/bzip2/Android.mk b/project/jni/bzip2/Android.mk new file mode 100644 index 000000000..fa6ac2ae4 --- /dev/null +++ b/project/jni/bzip2/Android.mk @@ -0,0 +1,21 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := bzip2 + +LOCAL_C_INCLUDES := $(LOCAL_PATH) $(LOCAL_PATH)/include +LOCAL_CFLAGS := -O3 -D__sF=__SDL_fake_stdout + +LOCAL_CPP_EXTENSION := .cpp + +LOCAL_SRC_FILES := $(notdir $(wildcard $(LOCAL_PATH)/*.c)) + +LOCAL_STATIC_LIBRARIES := + +LOCAL_SHARED_LIBRARIES := sdl-$(SDL_VERSION) + +LOCAL_LDLIBS := + +include $(BUILD_SHARED_LIBRARY) + diff --git a/project/jni/bzip2/CHANGES b/project/jni/bzip2/CHANGES new file mode 100644 index 000000000..81e97ca6f --- /dev/null +++ b/project/jni/bzip2/CHANGES @@ -0,0 +1,327 @@ + ------------------------------------------------------------------ + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ------------------------------------------------------------------ + + +0.9.0 +~~~~~ +First version. + + +0.9.0a +~~~~~~ +Removed 'ranlib' from Makefile, since most modern Unix-es +don't need it, or even know about it. + + +0.9.0b +~~~~~~ +Fixed a problem with error reporting in bzip2.c. This does not effect +the library in any way. Problem is: versions 0.9.0 and 0.9.0a (of the +program proper) compress and decompress correctly, but give misleading +error messages (internal panics) when an I/O error occurs, instead of +reporting the problem correctly. This shouldn't give any data loss +(as far as I can see), but is confusing. + +Made the inline declarations disappear for non-GCC compilers. + + +0.9.0c +~~~~~~ +Fixed some problems in the library pertaining to some boundary cases. +This makes the library behave more correctly in those situations. The +fixes apply only to features (calls and parameters) not used by +bzip2.c, so the non-fixedness of them in previous versions has no +effect on reliability of bzip2.c. + +In bzlib.c: + * made zero-length BZ_FLUSH work correctly in bzCompress(). + * fixed bzWrite/bzRead to ignore zero-length requests. + * fixed bzread to correctly handle read requests after EOF. + * wrong parameter order in call to bzDecompressInit in + bzBuffToBuffDecompress. Fixed. + +In compress.c: + * changed setting of nGroups in sendMTFValues() so as to + do a bit better on small files. This _does_ effect + bzip2.c. + + +0.9.5a +~~~~~~ +Major change: add a fallback sorting algorithm (blocksort.c) +to give reasonable behaviour even for very repetitive inputs. +Nuked --repetitive-best and --repetitive-fast since they are +no longer useful. + +Minor changes: mostly a whole bunch of small changes/ +bugfixes in the driver (bzip2.c). Changes pertaining to the +user interface are: + + allow decompression of symlink'd files to stdout + decompress/test files even without .bz2 extension + give more accurate error messages for I/O errors + when compressing/decompressing to stdout, don't catch control-C + read flags from BZIP2 and BZIP environment variables + decline to break hard links to a file unless forced with -f + allow -c flag even with no filenames + preserve file ownerships as far as possible + make -s -1 give the expected block size (100k) + add a flag -q --quiet to suppress nonessential warnings + stop decoding flags after --, so files beginning in - can be handled + resolved inconsistent naming: bzcat or bz2cat ? + bzip2 --help now returns 0 + +Programming-level changes are: + + fixed syntax error in GET_LL4 for Borland C++ 5.02 + let bzBuffToBuffDecompress return BZ_DATA_ERROR{_MAGIC} + fix overshoot of mode-string end in bzopen_or_bzdopen + wrapped bzlib.h in #ifdef __cplusplus ... extern "C" { ... } + close file handles under all error conditions + added minor mods so it compiles with DJGPP out of the box + fixed Makefile so it doesn't give problems with BSD make + fix uninitialised memory reads in dlltest.c + +0.9.5b +~~~~~~ +Open stdin/stdout in binary mode for DJGPP. + +0.9.5c +~~~~~~ +Changed BZ_N_OVERSHOOT to be ... + 2 instead of ... + 1. The + 1 +version could cause the sorted order to be wrong in some extremely +obscure cases. Also changed setting of quadrant in blocksort.c. + +0.9.5d +~~~~~~ +The only functional change is to make bzlibVersion() in the library +return the correct string. This has no effect whatsoever on the +functioning of the bzip2 program or library. Added a couple of casts +so the library compiles without warnings at level 3 in MS Visual +Studio 6.0. Included a Y2K statement in the file Y2K_INFO. All other +changes are minor documentation changes. + +1.0 +~~~ +Several minor bugfixes and enhancements: + +* Large file support. The library uses 64-bit counters to + count the volume of data passing through it. bzip2.c + is now compiled with -D_FILE_OFFSET_BITS=64 to get large + file support from the C library. -v correctly prints out + file sizes greater than 4 gigabytes. All these changes have + been made without assuming a 64-bit platform or a C compiler + which supports 64-bit ints, so, except for the C library + aspect, they are fully portable. + +* Decompression robustness. The library/program should be + robust to any corruption of compressed data, detecting and + handling _all_ corruption, instead of merely relying on + the CRCs. What this means is that the program should + never crash, given corrupted data, and the library should + always return BZ_DATA_ERROR. + +* Fixed an obscure race-condition bug only ever observed on + Solaris, in which, if you were very unlucky and issued + control-C at exactly the wrong time, both input and output + files would be deleted. + +* Don't run out of file handles on test/decompression when + large numbers of files have invalid magic numbers. + +* Avoid library namespace pollution. Prefix all exported + symbols with BZ2_. + +* Minor sorting enhancements from my DCC2000 paper. + +* Advance the version number to 1.0, so as to counteract the + (false-in-this-case) impression some people have that programs + with version numbers less than 1.0 are in some way, experimental, + pre-release versions. + +* Create an initial Makefile-libbz2_so to build a shared library. + Yes, I know I should really use libtool et al ... + +* Make the program exit with 2 instead of 0 when decompression + fails due to a bad magic number (ie, an invalid bzip2 header). + Also exit with 1 (as the manual claims :-) whenever a diagnostic + message would have been printed AND the corresponding operation + is aborted, for example + bzip2: Output file xx already exists. + When a diagnostic message is printed but the operation is not + aborted, for example + bzip2: Can't guess original name for wurble -- using wurble.out + then the exit value 0 is returned, unless some other problem is + also detected. + + I think it corresponds more closely to what the manual claims now. + + +1.0.1 +~~~~~ +* Modified dlltest.c so it uses the new BZ2_ naming scheme. +* Modified makefile-msc to fix minor build probs on Win2k. +* Updated README.COMPILATION.PROBLEMS. + +There are no functionality changes or bug fixes relative to version +1.0.0. This is just a documentation update + a fix for minor Win32 +build problems. For almost everyone, upgrading from 1.0.0 to 1.0.1 is +utterly pointless. Don't bother. + + +1.0.2 +~~~~~ +A bug fix release, addressing various minor issues which have appeared +in the 18 or so months since 1.0.1 was released. Most of the fixes +are to do with file-handling or documentation bugs. To the best of my +knowledge, there have been no data-loss-causing bugs reported in the +compression/decompression engine of 1.0.0 or 1.0.1. + +Note that this release does not improve the rather crude build system +for Unix platforms. The general plan here is to autoconfiscate/ +libtoolise 1.0.2 soon after release, and release the result as 1.1.0 +or perhaps 1.2.0. That, however, is still just a plan at this point. + +Here are the changes in 1.0.2. Bug-reporters and/or patch-senders in +parentheses. + +* Fix an infinite segfault loop in 1.0.1 when a directory is + encountered in -f (force) mode. + (Trond Eivind Glomsrod, Nicholas Nethercote, Volker Schmidt) + +* Avoid double fclose() of output file on certain I/O error paths. + (Solar Designer) + +* Don't fail with internal error 1007 when fed a long stream (> 48MB) + of byte 251. Also print useful message suggesting that 1007s may be + caused by bad memory. + (noticed by Juan Pedro Vallejo, fixed by me) + +* Fix uninitialised variable silly bug in demo prog dlltest.c. + (Jorj Bauer) + +* Remove 512-MB limitation on recovered file size for bzip2recover + on selected platforms which support 64-bit ints. At the moment + all GCC supported platforms, and Win32. + (me, Alson van der Meulen) + +* Hard-code header byte values, to give correct operation on platforms + using EBCDIC as their native character set (IBM's OS/390). + (Leland Lucius) + +* Copy file access times correctly. + (Marty Leisner) + +* Add distclean and check targets to Makefile. + (Michael Carmack) + +* Parameterise use of ar and ranlib in Makefile. Also add $(LDFLAGS). + (Rich Ireland, Bo Thorsen) + +* Pass -p (create parent dirs as needed) to mkdir during make install. + (Jeremy Fusco) + +* Dereference symlinks when copying file permissions in -f mode. + (Volker Schmidt) + +* Majorly simplify implementation of uInt64_qrm10. + (Bo Lindbergh) + +* Check the input file still exists before deleting the output one, + when aborting in cleanUpAndFail(). + (Joerg Prante, Robert Linden, Matthias Krings) + +Also a bunch of patches courtesy of Philippe Troin, the Debian maintainer +of bzip2: + +* Wrapper scripts (with manpages): bzdiff, bzgrep, bzmore. + +* Spelling changes and minor enhancements in bzip2.1. + +* Avoid race condition between creating the output file and setting its + interim permissions safely, by using fopen_output_safely(). + No changes to bzip2recover since there is no issue with file + permissions there. + +* do not print senseless report with -v when compressing an empty + file. + +* bzcat -f works on non-bzip2 files. + +* do not try to escape shell meta-characters on unix (the shell takes + care of these). + +* added --fast and --best aliases for -1 -9 for gzip compatibility. + + +1.0.3 (15 Feb 05) +~~~~~~~~~~~~~~~~~ +Fixes some minor bugs since the last version, 1.0.2. + +* Further robustification against corrupted compressed data. + There are currently no known bitstreams which can cause the + decompressor to crash, loop or access memory which does not + belong to it. If you are using bzip2 or the library to + decompress bitstreams from untrusted sources, an upgrade + to 1.0.3 is recommended. This fixes CAN-2005-1260. + +* The documentation has been converted to XML, from which html + and pdf can be derived. + +* Various minor bugs in the documentation have been fixed. + +* Fixes for various compilation warnings with newer versions of + gcc, and on 64-bit platforms. + +* The BZ_NO_STDIO cpp symbol was not properly observed in 1.0.2. + This has been fixed. + + +1.0.4 (20 Dec 06) +~~~~~~~~~~~~~~~~~ +Fixes some minor bugs since the last version, 1.0.3. + +* Fix file permissions race problem (CAN-2005-0953). + +* Avoid possible segfault in BZ2_bzclose. From Coverity's NetBSD + scan. + +* 'const'/prototype cleanups in the C code. + +* Change default install location to /usr/local, and handle multiple + 'make install's without error. + +* Sanitise file names more carefully in bzgrep. Fixes CAN-2005-0758 + to the extent that applies to bzgrep. + +* Use 'mktemp' rather than 'tempfile' in bzdiff. + +* Tighten up a couple of assertions in blocksort.c following automated + analysis. + +* Fix minor doc/comment bugs. + + +1.0.5 (10 Dec 07) +~~~~~~~~~~~~~~~~~ +Security fix only. Fixes CERT-FI 20469 as it applies to bzip2. + + +1.0.6 (6 Sept 10) +~~~~~~~~~~~~~~~~~ + +* Security fix for CVE-2010-0405. This was reported by Mikolaj + Izdebski. + +* Make the documentation build on Ubuntu 10.04 diff --git a/project/jni/bzip2/LICENSE b/project/jni/bzip2/LICENSE new file mode 100644 index 000000000..cc614178c --- /dev/null +++ b/project/jni/bzip2/LICENSE @@ -0,0 +1,42 @@ + +-------------------------------------------------------------------------- + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2010 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@bzip.org +bzip2/libbzip2 version 1.0.6 of 6 September 2010 + +-------------------------------------------------------------------------- diff --git a/project/jni/bzip2/Makefile b/project/jni/bzip2/Makefile new file mode 100644 index 000000000..9754ddf28 --- /dev/null +++ b/project/jni/bzip2/Makefile @@ -0,0 +1,217 @@ +# ------------------------------------------------------------------ +# This file is part of bzip2/libbzip2, a program and library for +# lossless, block-sorting data compression. +# +# bzip2/libbzip2 version 1.0.6 of 6 September 2010 +# Copyright (C) 1996-2010 Julian Seward +# +# Please read the WARNING, DISCLAIMER and PATENTS sections in the +# README file. +# +# This program is released under the terms of the license contained +# in the file LICENSE. +# ------------------------------------------------------------------ + +SHELL=/bin/sh + +# To assist in cross-compiling +CC=gcc +AR=ar +RANLIB=ranlib +LDFLAGS= + +BIGFILES=-D_FILE_OFFSET_BITS=64 +CFLAGS=-Wall -Winline -O2 -g $(BIGFILES) + +# Where you want it installed when you do 'make install' +PREFIX=/usr/local + + +OBJS= blocksort.o \ + huffman.o \ + crctable.o \ + randtable.o \ + compress.o \ + decompress.o \ + bzlib.o + +all: libbz2.a bzip2 bzip2recover test + +bzip2: libbz2.a bzip2.o + $(CC) $(CFLAGS) $(LDFLAGS) -o bzip2 bzip2.o -L. -lbz2 + +bzip2recover: bzip2recover.o + $(CC) $(CFLAGS) $(LDFLAGS) -o bzip2recover bzip2recover.o + +libbz2.a: $(OBJS) + rm -f libbz2.a + $(AR) cq libbz2.a $(OBJS) + @if ( test -f $(RANLIB) -o -f /usr/bin/ranlib -o \ + -f /bin/ranlib -o -f /usr/ccs/bin/ranlib ) ; then \ + echo $(RANLIB) libbz2.a ; \ + $(RANLIB) libbz2.a ; \ + fi + +check: test +test: bzip2 + @cat words1 + ./bzip2 -1 < sample1.ref > sample1.rb2 + ./bzip2 -2 < sample2.ref > sample2.rb2 + ./bzip2 -3 < sample3.ref > sample3.rb2 + ./bzip2 -d < sample1.bz2 > sample1.tst + ./bzip2 -d < sample2.bz2 > sample2.tst + ./bzip2 -ds < sample3.bz2 > sample3.tst + cmp sample1.bz2 sample1.rb2 + cmp sample2.bz2 sample2.rb2 + cmp sample3.bz2 sample3.rb2 + cmp sample1.tst sample1.ref + cmp sample2.tst sample2.ref + cmp sample3.tst sample3.ref + @cat words3 + +install: bzip2 bzip2recover + if ( test ! -d $(PREFIX)/bin ) ; then mkdir -p $(PREFIX)/bin ; fi + if ( test ! -d $(PREFIX)/lib ) ; then mkdir -p $(PREFIX)/lib ; fi + if ( test ! -d $(PREFIX)/man ) ; then mkdir -p $(PREFIX)/man ; fi + if ( test ! -d $(PREFIX)/man/man1 ) ; then mkdir -p $(PREFIX)/man/man1 ; fi + if ( test ! -d $(PREFIX)/include ) ; then mkdir -p $(PREFIX)/include ; fi + cp -f bzip2 $(PREFIX)/bin/bzip2 + cp -f bzip2 $(PREFIX)/bin/bunzip2 + cp -f bzip2 $(PREFIX)/bin/bzcat + cp -f bzip2recover $(PREFIX)/bin/bzip2recover + chmod a+x $(PREFIX)/bin/bzip2 + chmod a+x $(PREFIX)/bin/bunzip2 + chmod a+x $(PREFIX)/bin/bzcat + chmod a+x $(PREFIX)/bin/bzip2recover + cp -f bzip2.1 $(PREFIX)/man/man1 + chmod a+r $(PREFIX)/man/man1/bzip2.1 + cp -f bzlib.h $(PREFIX)/include + chmod a+r $(PREFIX)/include/bzlib.h + cp -f libbz2.a $(PREFIX)/lib + chmod a+r $(PREFIX)/lib/libbz2.a + cp -f bzgrep $(PREFIX)/bin/bzgrep + ln -s -f $(PREFIX)/bin/bzgrep $(PREFIX)/bin/bzegrep + ln -s -f $(PREFIX)/bin/bzgrep $(PREFIX)/bin/bzfgrep + chmod a+x $(PREFIX)/bin/bzgrep + cp -f bzmore $(PREFIX)/bin/bzmore + ln -s -f $(PREFIX)/bin/bzmore $(PREFIX)/bin/bzless + chmod a+x $(PREFIX)/bin/bzmore + cp -f bzdiff $(PREFIX)/bin/bzdiff + ln -s -f $(PREFIX)/bin/bzdiff $(PREFIX)/bin/bzcmp + chmod a+x $(PREFIX)/bin/bzdiff + cp -f bzgrep.1 bzmore.1 bzdiff.1 $(PREFIX)/man/man1 + chmod a+r $(PREFIX)/man/man1/bzgrep.1 + chmod a+r $(PREFIX)/man/man1/bzmore.1 + chmod a+r $(PREFIX)/man/man1/bzdiff.1 + echo ".so man1/bzgrep.1" > $(PREFIX)/man/man1/bzegrep.1 + echo ".so man1/bzgrep.1" > $(PREFIX)/man/man1/bzfgrep.1 + echo ".so man1/bzmore.1" > $(PREFIX)/man/man1/bzless.1 + echo ".so man1/bzdiff.1" > $(PREFIX)/man/man1/bzcmp.1 + +clean: + rm -f *.o libbz2.a bzip2 bzip2recover \ + sample1.rb2 sample2.rb2 sample3.rb2 \ + sample1.tst sample2.tst sample3.tst + +blocksort.o: blocksort.c + @cat words0 + $(CC) $(CFLAGS) -c blocksort.c +huffman.o: huffman.c + $(CC) $(CFLAGS) -c huffman.c +crctable.o: crctable.c + $(CC) $(CFLAGS) -c crctable.c +randtable.o: randtable.c + $(CC) $(CFLAGS) -c randtable.c +compress.o: compress.c + $(CC) $(CFLAGS) -c compress.c +decompress.o: decompress.c + $(CC) $(CFLAGS) -c decompress.c +bzlib.o: bzlib.c + $(CC) $(CFLAGS) -c bzlib.c +bzip2.o: bzip2.c + $(CC) $(CFLAGS) -c bzip2.c +bzip2recover.o: bzip2recover.c + $(CC) $(CFLAGS) -c bzip2recover.c + + +distclean: clean + rm -f manual.ps manual.html manual.pdf + +DISTNAME=bzip2-1.0.6 +dist: check manual + rm -f $(DISTNAME) + ln -s -f . $(DISTNAME) + tar cvf $(DISTNAME).tar \ + $(DISTNAME)/blocksort.c \ + $(DISTNAME)/huffman.c \ + $(DISTNAME)/crctable.c \ + $(DISTNAME)/randtable.c \ + $(DISTNAME)/compress.c \ + $(DISTNAME)/decompress.c \ + $(DISTNAME)/bzlib.c \ + $(DISTNAME)/bzip2.c \ + $(DISTNAME)/bzip2recover.c \ + $(DISTNAME)/bzlib.h \ + $(DISTNAME)/bzlib_private.h \ + $(DISTNAME)/Makefile \ + $(DISTNAME)/LICENSE \ + $(DISTNAME)/bzip2.1 \ + $(DISTNAME)/bzip2.1.preformatted \ + $(DISTNAME)/bzip2.txt \ + $(DISTNAME)/words0 \ + $(DISTNAME)/words1 \ + $(DISTNAME)/words2 \ + $(DISTNAME)/words3 \ + $(DISTNAME)/sample1.ref \ + $(DISTNAME)/sample2.ref \ + $(DISTNAME)/sample3.ref \ + $(DISTNAME)/sample1.bz2 \ + $(DISTNAME)/sample2.bz2 \ + $(DISTNAME)/sample3.bz2 \ + $(DISTNAME)/dlltest.c \ + $(DISTNAME)/manual.html \ + $(DISTNAME)/manual.pdf \ + $(DISTNAME)/manual.ps \ + $(DISTNAME)/README \ + $(DISTNAME)/README.COMPILATION.PROBLEMS \ + $(DISTNAME)/README.XML.STUFF \ + $(DISTNAME)/CHANGES \ + $(DISTNAME)/libbz2.def \ + $(DISTNAME)/libbz2.dsp \ + $(DISTNAME)/dlltest.dsp \ + $(DISTNAME)/makefile.msc \ + $(DISTNAME)/unzcrash.c \ + $(DISTNAME)/spewG.c \ + $(DISTNAME)/mk251.c \ + $(DISTNAME)/bzdiff \ + $(DISTNAME)/bzdiff.1 \ + $(DISTNAME)/bzmore \ + $(DISTNAME)/bzmore.1 \ + $(DISTNAME)/bzgrep \ + $(DISTNAME)/bzgrep.1 \ + $(DISTNAME)/Makefile-libbz2_so \ + $(DISTNAME)/bz-common.xsl \ + $(DISTNAME)/bz-fo.xsl \ + $(DISTNAME)/bz-html.xsl \ + $(DISTNAME)/bzip.css \ + $(DISTNAME)/entities.xml \ + $(DISTNAME)/manual.xml \ + $(DISTNAME)/format.pl \ + $(DISTNAME)/xmlproc.sh + gzip -v $(DISTNAME).tar + +# For rebuilding the manual from sources on my SuSE 9.1 box + +MANUAL_SRCS= bz-common.xsl bz-fo.xsl bz-html.xsl bzip.css \ + entities.xml manual.xml + +manual: manual.html manual.ps manual.pdf + +manual.ps: $(MANUAL_SRCS) + ./xmlproc.sh -ps manual.xml + +manual.pdf: $(MANUAL_SRCS) + ./xmlproc.sh -pdf manual.xml + +manual.html: $(MANUAL_SRCS) + ./xmlproc.sh -html manual.xml diff --git a/project/jni/bzip2/Makefile-libbz2_so b/project/jni/bzip2/Makefile-libbz2_so new file mode 100644 index 000000000..e58791b3b --- /dev/null +++ b/project/jni/bzip2/Makefile-libbz2_so @@ -0,0 +1,59 @@ + +# This Makefile builds a shared version of the library, +# libbz2.so.1.0.6, with soname libbz2.so.1.0, +# at least on x86-Linux (RedHat 7.2), +# with gcc-2.96 20000731 (Red Hat Linux 7.1 2.96-98). +# Please see the README file for some important info +# about building the library like this. + +# ------------------------------------------------------------------ +# This file is part of bzip2/libbzip2, a program and library for +# lossless, block-sorting data compression. +# +# bzip2/libbzip2 version 1.0.6 of 6 September 2010 +# Copyright (C) 1996-2010 Julian Seward +# +# Please read the WARNING, DISCLAIMER and PATENTS sections in the +# README file. +# +# This program is released under the terms of the license contained +# in the file LICENSE. +# ------------------------------------------------------------------ + + +SHELL=/bin/sh +CC=gcc +BIGFILES=-D_FILE_OFFSET_BITS=64 +CFLAGS=-fpic -fPIC -Wall -Winline -O2 -g $(BIGFILES) + +OBJS= blocksort.o \ + huffman.o \ + crctable.o \ + randtable.o \ + compress.o \ + decompress.o \ + bzlib.o + +all: $(OBJS) + $(CC) -shared -Wl,-soname -Wl,libbz2.so.1.0 -o libbz2.so.1.0.6 $(OBJS) + $(CC) $(CFLAGS) -o bzip2-shared bzip2.c libbz2.so.1.0.6 + rm -f libbz2.so.1.0 + ln -s libbz2.so.1.0.6 libbz2.so.1.0 + +clean: + rm -f $(OBJS) bzip2.o libbz2.so.1.0.6 libbz2.so.1.0 bzip2-shared + +blocksort.o: blocksort.c + $(CC) $(CFLAGS) -c blocksort.c +huffman.o: huffman.c + $(CC) $(CFLAGS) -c huffman.c +crctable.o: crctable.c + $(CC) $(CFLAGS) -c crctable.c +randtable.o: randtable.c + $(CC) $(CFLAGS) -c randtable.c +compress.o: compress.c + $(CC) $(CFLAGS) -c compress.c +decompress.o: decompress.c + $(CC) $(CFLAGS) -c decompress.c +bzlib.o: bzlib.c + $(CC) $(CFLAGS) -c bzlib.c diff --git a/project/jni/bzip2/README b/project/jni/bzip2/README new file mode 100644 index 000000000..9fb0f6360 --- /dev/null +++ b/project/jni/bzip2/README @@ -0,0 +1,215 @@ + +This is the README for bzip2/libzip2. +This version is fully compatible with the previous public releases. + +------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.6 of 6 September 2010 +Copyright (C) 1996-2010 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in this file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ + +Complete documentation is available in Postscript form (manual.ps), +PDF (manual.pdf) or html (manual.html). A plain-text version of the +manual page is available as bzip2.txt. + + +HOW TO BUILD -- UNIX + +Type 'make'. This builds the library libbz2.a and then the programs +bzip2 and bzip2recover. Six self-tests are run. If the self-tests +complete ok, carry on to installation: + +To install in /usr/local/bin, /usr/local/lib, /usr/local/man and +/usr/local/include, type + + make install + +To install somewhere else, eg, /xxx/yyy/{bin,lib,man,include}, type + + make install PREFIX=/xxx/yyy + +If you are (justifiably) paranoid and want to see what 'make install' +is going to do, you can first do + + make -n install or + make -n install PREFIX=/xxx/yyy respectively. + +The -n instructs make to show the commands it would execute, but not +actually execute them. + + +HOW TO BUILD -- UNIX, shared library libbz2.so. + +Do 'make -f Makefile-libbz2_so'. This Makefile seems to work for +Linux-ELF (RedHat 7.2 on an x86 box), with gcc. I make no claims +that it works for any other platform, though I suspect it probably +will work for most platforms employing both ELF and gcc. + +bzip2-shared, a client of the shared library, is also built, but not +self-tested. So I suggest you also build using the normal Makefile, +since that conducts a self-test. A second reason to prefer the +version statically linked to the library is that, on x86 platforms, +building shared objects makes a valuable register (%ebx) unavailable +to gcc, resulting in a slowdown of 10%-20%, at least for bzip2. + +Important note for people upgrading .so's from 0.9.0/0.9.5 to version +1.0.X. All the functions in the library have been renamed, from (eg) +bzCompress to BZ2_bzCompress, to avoid namespace pollution. +Unfortunately this means that the libbz2.so created by +Makefile-libbz2_so will not work with any program which used an older +version of the library. I do encourage library clients to make the +effort to upgrade to use version 1.0, since it is both faster and more +robust than previous versions. + + +HOW TO BUILD -- Windows 95, NT, DOS, Mac, etc. + +It's difficult for me to support compilation on all these platforms. +My approach is to collect binaries for these platforms, and put them +on the master web site (http://www.bzip.org). Look there. However +(FWIW), bzip2-1.0.X is very standard ANSI C and should compile +unmodified with MS Visual C. If you have difficulties building, you +might want to read README.COMPILATION.PROBLEMS. + +At least using MS Visual C++ 6, you can build from the unmodified +sources by issuing, in a command shell: + + nmake -f makefile.msc + +(you may need to first run the MSVC-provided script VCVARS32.BAT + so as to set up paths to the MSVC tools correctly). + + +VALIDATION + +Correct operation, in the sense that a compressed file can always be +decompressed to reproduce the original, is obviously of paramount +importance. To validate bzip2, I used a modified version of Mark +Nelson's churn program. Churn is an automated test driver which +recursively traverses a directory structure, using bzip2 to compress +and then decompress each file it encounters, and checking that the +decompressed data is the same as the original. + + + +Please read and be aware of the following: + +WARNING: + + This program and library (attempts to) compress data by + performing several non-trivial transformations on it. + Unless you are 100% familiar with *all* the algorithms + contained herein, and with the consequences of modifying them, + you should NOT meddle with the compression or decompression + machinery. Incorrect changes can and very likely *will* + lead to disastrous loss of data. + + +DISCLAIMER: + + I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE + USE OF THIS PROGRAM/LIBRARY, HOWSOEVER CAUSED. + + Every compression of a file implies an assumption that the + compressed file can be decompressed to reproduce the original. + Great efforts in design, coding and testing have been made to + ensure that this program works correctly. However, the complexity + of the algorithms, and, in particular, the presence of various + special cases in the code which occur with very low but non-zero + probability make it impossible to rule out the possibility of bugs + remaining in the program. DO NOT COMPRESS ANY DATA WITH THIS + PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE POSSIBILITY, HOWEVER + SMALL, THAT THE DATA WILL NOT BE RECOVERABLE. + + That is not to say this program is inherently unreliable. + Indeed, I very much hope the opposite is true. bzip2/libbzip2 + has been carefully constructed and extensively tested. + + +PATENTS: + + To the best of my knowledge, bzip2/libbzip2 does not use any + patented algorithms. However, I do not have the resources + to carry out a patent search. Therefore I cannot give any + guarantee of the above statement. + + + +WHAT'S NEW IN 0.9.0 (as compared to 0.1pl2) ? + + * Approx 10% faster compression, 30% faster decompression + * -t (test mode) is a lot quicker + * Can decompress concatenated compressed files + * Programming interface, so programs can directly read/write .bz2 files + * Less restrictive (BSD-style) licensing + * Flag handling more compatible with GNU gzip + * Much more documentation, i.e., a proper user manual + * Hopefully, improved portability (at least of the library) + +WHAT'S NEW IN 0.9.5 ? + + * Compression speed is much less sensitive to the input + data than in previous versions. Specifically, the very + slow performance caused by repetitive data is fixed. + * Many small improvements in file and flag handling. + * A Y2K statement. + +WHAT'S NEW IN 1.0.0 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.2 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.3 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.4 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.5 ? + + See the CHANGES file. + +WHAT'S NEW IN 1.0.6 ? + + See the CHANGES file. + + +I hope you find bzip2 useful. Feel free to contact me at + jseward@bzip.org +if you have any suggestions or queries. Many people mailed me with +comments, suggestions and patches after the releases of bzip-0.15, +bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1, +1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this +feedback. I thank you for your comments. + +bzip2's "home" is http://www.bzip.org/ + +Julian Seward +jseward@bzip.org +Cambridge, UK. + +18 July 1996 (version 0.15) +25 August 1996 (version 0.21) + 7 August 1997 (bzip2, version 0.1) +29 August 1997 (bzip2, version 0.1pl2) +23 August 1998 (bzip2, version 0.9.0) + 8 June 1999 (bzip2, version 0.9.5) + 4 Sept 1999 (bzip2, version 0.9.5d) + 5 May 2000 (bzip2, version 1.0pre8) +30 December 2001 (bzip2, version 1.0.2pre1) +15 February 2005 (bzip2, version 1.0.3) +20 December 2006 (bzip2, version 1.0.4) +10 December 2007 (bzip2, version 1.0.5) + 6 Sept 2010 (bzip2, version 1.0.6) diff --git a/project/jni/bzip2/README.COMPILATION.PROBLEMS b/project/jni/bzip2/README.COMPILATION.PROBLEMS new file mode 100644 index 000000000..667d0d6df --- /dev/null +++ b/project/jni/bzip2/README.COMPILATION.PROBLEMS @@ -0,0 +1,58 @@ +------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.6 of 6 September 2010 +Copyright (C) 1996-2010 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ + +bzip2-1.0.6 should compile without problems on the vast majority of +platforms. Using the supplied Makefile, I've built and tested it +myself for x86-linux and amd64-linux. With makefile.msc, Visual C++ +6.0 and nmake, you can build a native Win32 version too. Large file +support seems to work correctly on at least on amd64-linux. + +When I say "large file" I mean a file of size 2,147,483,648 (2^31) +bytes or above. Many older OSs can't handle files above this size, +but many newer ones can. Large files are pretty huge -- most files +you'll encounter are not Large Files. + +Early versions of bzip2 (0.1, 0.9.0, 0.9.5) compiled on a wide variety +of platforms without difficulty, and I hope this version will continue +in that tradition. However, in order to support large files, I've had +to include the define -D_FILE_OFFSET_BITS=64 in the Makefile. This +can cause problems. + +The technique of adding -D_FILE_OFFSET_BITS=64 to get large file +support is, as far as I know, the Recommended Way to get correct large +file support. For more details, see the Large File Support +Specification, published by the Large File Summit, at + + http://ftp.sas.com/standards/large.file + +As a general comment, if you get compilation errors which you think +are related to large file support, try removing the above define from +the Makefile, ie, delete the line + + BIGFILES=-D_FILE_OFFSET_BITS=64 + +from the Makefile, and do 'make clean ; make'. This will give you a +version of bzip2 without large file support, which, for most +applications, is probably not a problem. + +Alternatively, try some of the platform-specific hints listed below. + +You can use the spewG.c program to generate huge files to test bzip2's +large file support, if you are feeling paranoid. Be aware though that +any compilation problems which affect bzip2 will also affect spewG.c, +alas. + +AIX: I have reports that for large file support, you need to specify +-D_LARGE_FILES rather than -D_FILE_OFFSET_BITS=64. I have not tested +this myself. diff --git a/project/jni/bzip2/README.XML.STUFF b/project/jni/bzip2/README.XML.STUFF new file mode 100644 index 000000000..3a57f3fa8 --- /dev/null +++ b/project/jni/bzip2/README.XML.STUFF @@ -0,0 +1,45 @@ + ---------------------------------------------------------------- + This file is part of bzip2/libbzip2, a program and library for + lossless, block-sorting data compression. + + bzip2/libbzip2 version 1.0.6 of 6 September 2010 + Copyright (C) 1996-2010 Julian Seward + + Please read the WARNING, DISCLAIMER and PATENTS sections in the + README file. + + This program is released under the terms of the license contained + in the file LICENSE. + ---------------------------------------------------------------- + +The script xmlproc.sh takes an xml file as input, +and processes it to create .pdf, .html or .ps output. +It uses format.pl, a perl script to format
 blocks nicely,
+ and add CDATA tags so writers do not have to use eg. < 
+
+The file "entities.xml" must be edited to reflect current
+version, year, etc.
+
+
+Usage:
+
+  ./xmlproc.sh -v manual.xml
+  Validates an xml file to ensure no dtd-compliance errors
+
+  ./xmlproc.sh -html manual.xml
+  Output: manual.html
+
+  ./xmlproc.sh -pdf manual.xml
+  Output: manual.pdf
+
+  ./xmlproc.sh -ps manual.xml
+  Output: manual.ps
+
+
+Notum bene: 
+- pdfxmltex barfs if given a filename with an underscore in it
+
+- xmltex won't work yet - there's a bug in passivetex
+    which we are all waiting for Sebastian to fix.
+  So we are going the xml -> pdf -> ps route for the time being,
+    using pdfxmltex.
diff --git a/project/jni/bzip2/blocksort.c b/project/jni/bzip2/blocksort.c
new file mode 100644
index 000000000..d0d662cd4
--- /dev/null
+++ b/project/jni/bzip2/blocksort.c
@@ -0,0 +1,1094 @@
+
+/*-------------------------------------------------------------*/
+/*--- Block sorting machinery                               ---*/
+/*---                                           blocksort.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*---------------------------------------------*/
+/*--- Fallback O(N log(N)^2) sorting        ---*/
+/*--- algorithm, for repetitive blocks      ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static 
+__inline__
+void fallbackSimpleSort ( UInt32* fmap, 
+                          UInt32* eclass, 
+                          Int32   lo, 
+                          Int32   hi )
+{
+   Int32 i, j, tmp;
+   UInt32 ec_tmp;
+
+   if (lo == hi) return;
+
+   if (hi - lo > 3) {
+      for ( i = hi-4; i >= lo; i-- ) {
+         tmp = fmap[i];
+         ec_tmp = eclass[tmp];
+         for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 )
+            fmap[j-4] = fmap[j];
+         fmap[j-4] = tmp;
+      }
+   }
+
+   for ( i = hi-1; i >= lo; i-- ) {
+      tmp = fmap[i];
+      ec_tmp = eclass[tmp];
+      for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ )
+         fmap[j-1] = fmap[j];
+      fmap[j-1] = tmp;
+   }
+}
+
+
+/*---------------------------------------------*/
+#define fswap(zz1, zz2) \
+   { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
+
+#define fvswap(zzp1, zzp2, zzn)       \
+{                                     \
+   Int32 yyp1 = (zzp1);               \
+   Int32 yyp2 = (zzp2);               \
+   Int32 yyn  = (zzn);                \
+   while (yyn > 0) {                  \
+      fswap(fmap[yyp1], fmap[yyp2]);  \
+      yyp1++; yyp2++; yyn--;          \
+   }                                  \
+}
+
+
+#define fmin(a,b) ((a) < (b)) ? (a) : (b)
+
+#define fpush(lz,hz) { stackLo[sp] = lz; \
+                       stackHi[sp] = hz; \
+                       sp++; }
+
+#define fpop(lz,hz) { sp--;              \
+                      lz = stackLo[sp];  \
+                      hz = stackHi[sp]; }
+
+#define FALLBACK_QSORT_SMALL_THRESH 10
+#define FALLBACK_QSORT_STACK_SIZE   100
+
+
+static
+void fallbackQSort3 ( UInt32* fmap, 
+                      UInt32* eclass,
+                      Int32   loSt, 
+                      Int32   hiSt )
+{
+   Int32 unLo, unHi, ltLo, gtHi, n, m;
+   Int32 sp, lo, hi;
+   UInt32 med, r, r3;
+   Int32 stackLo[FALLBACK_QSORT_STACK_SIZE];
+   Int32 stackHi[FALLBACK_QSORT_STACK_SIZE];
+
+   r = 0;
+
+   sp = 0;
+   fpush ( loSt, hiSt );
+
+   while (sp > 0) {
+
+      AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 );
+
+      fpop ( lo, hi );
+      if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) {
+         fallbackSimpleSort ( fmap, eclass, lo, hi );
+         continue;
+      }
+
+      /* Random partitioning.  Median of 3 sometimes fails to
+         avoid bad cases.  Median of 9 seems to help but 
+         looks rather expensive.  This too seems to work but
+         is cheaper.  Guidance for the magic constants 
+         7621 and 32768 is taken from Sedgewick's algorithms
+         book, chapter 35.
+      */
+      r = ((r * 7621) + 1) % 32768;
+      r3 = r % 3;
+      if (r3 == 0) med = eclass[fmap[lo]]; else
+      if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else
+                   med = eclass[fmap[hi]];
+
+      unLo = ltLo = lo;
+      unHi = gtHi = hi;
+
+      while (1) {
+         while (1) {
+            if (unLo > unHi) break;
+            n = (Int32)eclass[fmap[unLo]] - (Int32)med;
+            if (n == 0) { 
+               fswap(fmap[unLo], fmap[ltLo]); 
+               ltLo++; unLo++; 
+               continue; 
+            };
+            if (n > 0) break;
+            unLo++;
+         }
+         while (1) {
+            if (unLo > unHi) break;
+            n = (Int32)eclass[fmap[unHi]] - (Int32)med;
+            if (n == 0) { 
+               fswap(fmap[unHi], fmap[gtHi]); 
+               gtHi--; unHi--; 
+               continue; 
+            };
+            if (n < 0) break;
+            unHi--;
+         }
+         if (unLo > unHi) break;
+         fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--;
+      }
+
+      AssertD ( unHi == unLo-1, "fallbackQSort3(2)" );
+
+      if (gtHi < ltLo) continue;
+
+      n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n);
+      m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m);
+
+      n = lo + unLo - ltLo - 1;
+      m = hi - (gtHi - unHi) + 1;
+
+      if (n - lo > hi - m) {
+         fpush ( lo, n );
+         fpush ( m, hi );
+      } else {
+         fpush ( m, hi );
+         fpush ( lo, n );
+      }
+   }
+}
+
+#undef fmin
+#undef fpush
+#undef fpop
+#undef fswap
+#undef fvswap
+#undef FALLBACK_QSORT_SMALL_THRESH
+#undef FALLBACK_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+      nblock > 0
+      eclass exists for [0 .. nblock-1]
+      ((UChar*)eclass) [0 .. nblock-1] holds block
+      ptr exists for [0 .. nblock-1]
+
+   Post:
+      ((UChar*)eclass) [0 .. nblock-1] holds block
+      All other areas of eclass destroyed
+      fmap [0 .. nblock-1] holds sorted order
+      bhtab [ 0 .. 2+(nblock/32) ] destroyed
+*/
+
+#define       SET_BH(zz)  bhtab[(zz) >> 5] |= (1 << ((zz) & 31))
+#define     CLEAR_BH(zz)  bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31))
+#define     ISSET_BH(zz)  (bhtab[(zz) >> 5] & (1 << ((zz) & 31)))
+#define      WORD_BH(zz)  bhtab[(zz) >> 5]
+#define UNALIGNED_BH(zz)  ((zz) & 0x01f)
+
+static
+void fallbackSort ( UInt32* fmap, 
+                    UInt32* eclass, 
+                    UInt32* bhtab,
+                    Int32   nblock,
+                    Int32   verb )
+{
+   Int32 ftab[257];
+   Int32 ftabCopy[256];
+   Int32 H, i, j, k, l, r, cc, cc1;
+   Int32 nNotDone;
+   Int32 nBhtab;
+   UChar* eclass8 = (UChar*)eclass;
+
+   /*--
+      Initial 1-char radix sort to generate
+      initial fmap and initial BH bits.
+   --*/
+   if (verb >= 4)
+      VPrintf0 ( "        bucket sorting ...\n" );
+   for (i = 0; i < 257;    i++) ftab[i] = 0;
+   for (i = 0; i < nblock; i++) ftab[eclass8[i]]++;
+   for (i = 0; i < 256;    i++) ftabCopy[i] = ftab[i];
+   for (i = 1; i < 257;    i++) ftab[i] += ftab[i-1];
+
+   for (i = 0; i < nblock; i++) {
+      j = eclass8[i];
+      k = ftab[j] - 1;
+      ftab[j] = k;
+      fmap[k] = i;
+   }
+
+   nBhtab = 2 + (nblock / 32);
+   for (i = 0; i < nBhtab; i++) bhtab[i] = 0;
+   for (i = 0; i < 256; i++) SET_BH(ftab[i]);
+
+   /*--
+      Inductively refine the buckets.  Kind-of an
+      "exponential radix sort" (!), inspired by the
+      Manber-Myers suffix array construction algorithm.
+   --*/
+
+   /*-- set sentinel bits for block-end detection --*/
+   for (i = 0; i < 32; i++) { 
+      SET_BH(nblock + 2*i);
+      CLEAR_BH(nblock + 2*i + 1);
+   }
+
+   /*-- the log(N) loop --*/
+   H = 1;
+   while (1) {
+
+      if (verb >= 4) 
+         VPrintf1 ( "        depth %6d has ", H );
+
+      j = 0;
+      for (i = 0; i < nblock; i++) {
+         if (ISSET_BH(i)) j = i;
+         k = fmap[i] - H; if (k < 0) k += nblock;
+         eclass[k] = j;
+      }
+
+      nNotDone = 0;
+      r = -1;
+      while (1) {
+
+	 /*-- find the next non-singleton bucket --*/
+         k = r + 1;
+         while (ISSET_BH(k) && UNALIGNED_BH(k)) k++;
+         if (ISSET_BH(k)) {
+            while (WORD_BH(k) == 0xffffffff) k += 32;
+            while (ISSET_BH(k)) k++;
+         }
+         l = k - 1;
+         if (l >= nblock) break;
+         while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++;
+         if (!ISSET_BH(k)) {
+            while (WORD_BH(k) == 0x00000000) k += 32;
+            while (!ISSET_BH(k)) k++;
+         }
+         r = k - 1;
+         if (r >= nblock) break;
+
+         /*-- now [l, r] bracket current bucket --*/
+         if (r > l) {
+            nNotDone += (r - l + 1);
+            fallbackQSort3 ( fmap, eclass, l, r );
+
+            /*-- scan bucket and generate header bits-- */
+            cc = -1;
+            for (i = l; i <= r; i++) {
+               cc1 = eclass[fmap[i]];
+               if (cc != cc1) { SET_BH(i); cc = cc1; };
+            }
+         }
+      }
+
+      if (verb >= 4) 
+         VPrintf1 ( "%6d unresolved strings\n", nNotDone );
+
+      H *= 2;
+      if (H > nblock || nNotDone == 0) break;
+   }
+
+   /*-- 
+      Reconstruct the original block in
+      eclass8 [0 .. nblock-1], since the
+      previous phase destroyed it.
+   --*/
+   if (verb >= 4)
+      VPrintf0 ( "        reconstructing block ...\n" );
+   j = 0;
+   for (i = 0; i < nblock; i++) {
+      while (ftabCopy[j] == 0) j++;
+      ftabCopy[j]--;
+      eclass8[fmap[i]] = (UChar)j;
+   }
+   AssertH ( j < 256, 1005 );
+}
+
+#undef       SET_BH
+#undef     CLEAR_BH
+#undef     ISSET_BH
+#undef      WORD_BH
+#undef UNALIGNED_BH
+
+
+/*---------------------------------------------*/
+/*--- The main, O(N^2 log(N)) sorting       ---*/
+/*--- algorithm.  Faster for "normal"       ---*/
+/*--- non-repetitive blocks.                ---*/
+/*---------------------------------------------*/
+
+/*---------------------------------------------*/
+static
+__inline__
+Bool mainGtU ( UInt32  i1, 
+               UInt32  i2,
+               UChar*  block, 
+               UInt16* quadrant,
+               UInt32  nblock,
+               Int32*  budget )
+{
+   Int32  k;
+   UChar  c1, c2;
+   UInt16 s1, s2;
+
+   AssertD ( i1 != i2, "mainGtU" );
+   /* 1 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 2 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 3 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 4 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 5 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 6 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 7 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 8 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 9 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 10 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 11 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+   /* 12 */
+   c1 = block[i1]; c2 = block[i2];
+   if (c1 != c2) return (c1 > c2);
+   i1++; i2++;
+
+   k = nblock + 8;
+
+   do {
+      /* 1 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 2 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 3 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 4 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 5 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 6 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 7 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+      /* 8 */
+      c1 = block[i1]; c2 = block[i2];
+      if (c1 != c2) return (c1 > c2);
+      s1 = quadrant[i1]; s2 = quadrant[i2];
+      if (s1 != s2) return (s1 > s2);
+      i1++; i2++;
+
+      if (i1 >= nblock) i1 -= nblock;
+      if (i2 >= nblock) i2 -= nblock;
+
+      k -= 8;
+      (*budget)--;
+   }
+      while (k >= 0);
+
+   return False;
+}
+
+
+/*---------------------------------------------*/
+/*--
+   Knuth's increments seem to work better
+   than Incerpi-Sedgewick here.  Possibly
+   because the number of elems to sort is
+   usually small, typically <= 20.
+--*/
+static
+Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280,
+                   9841, 29524, 88573, 265720,
+                   797161, 2391484 };
+
+static
+void mainSimpleSort ( UInt32* ptr,
+                      UChar*  block,
+                      UInt16* quadrant,
+                      Int32   nblock,
+                      Int32   lo, 
+                      Int32   hi, 
+                      Int32   d,
+                      Int32*  budget )
+{
+   Int32 i, j, h, bigN, hp;
+   UInt32 v;
+
+   bigN = hi - lo + 1;
+   if (bigN < 2) return;
+
+   hp = 0;
+   while (incs[hp] < bigN) hp++;
+   hp--;
+
+   for (; hp >= 0; hp--) {
+      h = incs[hp];
+
+      i = lo + h;
+      while (True) {
+
+         /*-- copy 1 --*/
+         if (i > hi) break;
+         v = ptr[i];
+         j = i;
+         while ( mainGtU ( 
+                    ptr[j-h]+d, v+d, block, quadrant, nblock, budget 
+                 ) ) {
+            ptr[j] = ptr[j-h];
+            j = j - h;
+            if (j <= (lo + h - 1)) break;
+         }
+         ptr[j] = v;
+         i++;
+
+         /*-- copy 2 --*/
+         if (i > hi) break;
+         v = ptr[i];
+         j = i;
+         while ( mainGtU ( 
+                    ptr[j-h]+d, v+d, block, quadrant, nblock, budget 
+                 ) ) {
+            ptr[j] = ptr[j-h];
+            j = j - h;
+            if (j <= (lo + h - 1)) break;
+         }
+         ptr[j] = v;
+         i++;
+
+         /*-- copy 3 --*/
+         if (i > hi) break;
+         v = ptr[i];
+         j = i;
+         while ( mainGtU ( 
+                    ptr[j-h]+d, v+d, block, quadrant, nblock, budget 
+                 ) ) {
+            ptr[j] = ptr[j-h];
+            j = j - h;
+            if (j <= (lo + h - 1)) break;
+         }
+         ptr[j] = v;
+         i++;
+
+         if (*budget < 0) return;
+      }
+   }
+}
+
+
+/*---------------------------------------------*/
+/*--
+   The following is an implementation of
+   an elegant 3-way quicksort for strings,
+   described in a paper "Fast Algorithms for
+   Sorting and Searching Strings", by Robert
+   Sedgewick and Jon L. Bentley.
+--*/
+
+#define mswap(zz1, zz2) \
+   { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; }
+
+#define mvswap(zzp1, zzp2, zzn)       \
+{                                     \
+   Int32 yyp1 = (zzp1);               \
+   Int32 yyp2 = (zzp2);               \
+   Int32 yyn  = (zzn);                \
+   while (yyn > 0) {                  \
+      mswap(ptr[yyp1], ptr[yyp2]);    \
+      yyp1++; yyp2++; yyn--;          \
+   }                                  \
+}
+
+static 
+__inline__
+UChar mmed3 ( UChar a, UChar b, UChar c )
+{
+   UChar t;
+   if (a > b) { t = a; a = b; b = t; };
+   if (b > c) { 
+      b = c;
+      if (a > b) b = a;
+   }
+   return b;
+}
+
+#define mmin(a,b) ((a) < (b)) ? (a) : (b)
+
+#define mpush(lz,hz,dz) { stackLo[sp] = lz; \
+                          stackHi[sp] = hz; \
+                          stackD [sp] = dz; \
+                          sp++; }
+
+#define mpop(lz,hz,dz) { sp--;             \
+                         lz = stackLo[sp]; \
+                         hz = stackHi[sp]; \
+                         dz = stackD [sp]; }
+
+
+#define mnextsize(az) (nextHi[az]-nextLo[az])
+
+#define mnextswap(az,bz)                                        \
+   { Int32 tz;                                                  \
+     tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \
+     tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \
+     tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; }
+
+
+#define MAIN_QSORT_SMALL_THRESH 20
+#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT)
+#define MAIN_QSORT_STACK_SIZE 100
+
+static
+void mainQSort3 ( UInt32* ptr,
+                  UChar*  block,
+                  UInt16* quadrant,
+                  Int32   nblock,
+                  Int32   loSt, 
+                  Int32   hiSt, 
+                  Int32   dSt,
+                  Int32*  budget )
+{
+   Int32 unLo, unHi, ltLo, gtHi, n, m, med;
+   Int32 sp, lo, hi, d;
+
+   Int32 stackLo[MAIN_QSORT_STACK_SIZE];
+   Int32 stackHi[MAIN_QSORT_STACK_SIZE];
+   Int32 stackD [MAIN_QSORT_STACK_SIZE];
+
+   Int32 nextLo[3];
+   Int32 nextHi[3];
+   Int32 nextD [3];
+
+   sp = 0;
+   mpush ( loSt, hiSt, dSt );
+
+   while (sp > 0) {
+
+      AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 );
+
+      mpop ( lo, hi, d );
+      if (hi - lo < MAIN_QSORT_SMALL_THRESH || 
+          d > MAIN_QSORT_DEPTH_THRESH) {
+         mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget );
+         if (*budget < 0) return;
+         continue;
+      }
+
+      med = (Int32) 
+            mmed3 ( block[ptr[ lo         ]+d],
+                    block[ptr[ hi         ]+d],
+                    block[ptr[ (lo+hi)>>1 ]+d] );
+
+      unLo = ltLo = lo;
+      unHi = gtHi = hi;
+
+      while (True) {
+         while (True) {
+            if (unLo > unHi) break;
+            n = ((Int32)block[ptr[unLo]+d]) - med;
+            if (n == 0) { 
+               mswap(ptr[unLo], ptr[ltLo]); 
+               ltLo++; unLo++; continue; 
+            };
+            if (n >  0) break;
+            unLo++;
+         }
+         while (True) {
+            if (unLo > unHi) break;
+            n = ((Int32)block[ptr[unHi]+d]) - med;
+            if (n == 0) { 
+               mswap(ptr[unHi], ptr[gtHi]); 
+               gtHi--; unHi--; continue; 
+            };
+            if (n <  0) break;
+            unHi--;
+         }
+         if (unLo > unHi) break;
+         mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--;
+      }
+
+      AssertD ( unHi == unLo-1, "mainQSort3(2)" );
+
+      if (gtHi < ltLo) {
+         mpush(lo, hi, d+1 );
+         continue;
+      }
+
+      n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n);
+      m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m);
+
+      n = lo + unLo - ltLo - 1;
+      m = hi - (gtHi - unHi) + 1;
+
+      nextLo[0] = lo;  nextHi[0] = n;   nextD[0] = d;
+      nextLo[1] = m;   nextHi[1] = hi;  nextD[1] = d;
+      nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1;
+
+      if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
+      if (mnextsize(1) < mnextsize(2)) mnextswap(1,2);
+      if (mnextsize(0) < mnextsize(1)) mnextswap(0,1);
+
+      AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" );
+      AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" );
+
+      mpush (nextLo[0], nextHi[0], nextD[0]);
+      mpush (nextLo[1], nextHi[1], nextD[1]);
+      mpush (nextLo[2], nextHi[2], nextD[2]);
+   }
+}
+
+#undef mswap
+#undef mvswap
+#undef mpush
+#undef mpop
+#undef mmin
+#undef mnextsize
+#undef mnextswap
+#undef MAIN_QSORT_SMALL_THRESH
+#undef MAIN_QSORT_DEPTH_THRESH
+#undef MAIN_QSORT_STACK_SIZE
+
+
+/*---------------------------------------------*/
+/* Pre:
+      nblock > N_OVERSHOOT
+      block32 exists for [0 .. nblock-1 +N_OVERSHOOT]
+      ((UChar*)block32) [0 .. nblock-1] holds block
+      ptr exists for [0 .. nblock-1]
+
+   Post:
+      ((UChar*)block32) [0 .. nblock-1] holds block
+      All other areas of block32 destroyed
+      ftab [0 .. 65536 ] destroyed
+      ptr [0 .. nblock-1] holds sorted order
+      if (*budget < 0), sorting was abandoned
+*/
+
+#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8])
+#define SETMASK (1 << 21)
+#define CLEARMASK (~(SETMASK))
+
+static
+void mainSort ( UInt32* ptr, 
+                UChar*  block,
+                UInt16* quadrant, 
+                UInt32* ftab,
+                Int32   nblock,
+                Int32   verb,
+                Int32*  budget )
+{
+   Int32  i, j, k, ss, sb;
+   Int32  runningOrder[256];
+   Bool   bigDone[256];
+   Int32  copyStart[256];
+   Int32  copyEnd  [256];
+   UChar  c1;
+   Int32  numQSorted;
+   UInt16 s;
+   if (verb >= 4) VPrintf0 ( "        main sort initialise ...\n" );
+
+   /*-- set up the 2-byte frequency table --*/
+   for (i = 65536; i >= 0; i--) ftab[i] = 0;
+
+   j = block[0] << 8;
+   i = nblock-1;
+   for (; i >= 3; i -= 4) {
+      quadrant[i] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i]) << 8);
+      ftab[j]++;
+      quadrant[i-1] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i-1]) << 8);
+      ftab[j]++;
+      quadrant[i-2] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i-2]) << 8);
+      ftab[j]++;
+      quadrant[i-3] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i-3]) << 8);
+      ftab[j]++;
+   }
+   for (; i >= 0; i--) {
+      quadrant[i] = 0;
+      j = (j >> 8) | ( ((UInt16)block[i]) << 8);
+      ftab[j]++;
+   }
+
+   /*-- (emphasises close relationship of block & quadrant) --*/
+   for (i = 0; i < BZ_N_OVERSHOOT; i++) {
+      block   [nblock+i] = block[i];
+      quadrant[nblock+i] = 0;
+   }
+
+   if (verb >= 4) VPrintf0 ( "        bucket sorting ...\n" );
+
+   /*-- Complete the initial radix sort --*/
+   for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1];
+
+   s = block[0] << 8;
+   i = nblock-1;
+   for (; i >= 3; i -= 4) {
+      s = (s >> 8) | (block[i] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i;
+      s = (s >> 8) | (block[i-1] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i-1;
+      s = (s >> 8) | (block[i-2] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i-2;
+      s = (s >> 8) | (block[i-3] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i-3;
+   }
+   for (; i >= 0; i--) {
+      s = (s >> 8) | (block[i] << 8);
+      j = ftab[s] -1;
+      ftab[s] = j;
+      ptr[j] = i;
+   }
+
+   /*--
+      Now ftab contains the first loc of every small bucket.
+      Calculate the running order, from smallest to largest
+      big bucket.
+   --*/
+   for (i = 0; i <= 255; i++) {
+      bigDone     [i] = False;
+      runningOrder[i] = i;
+   }
+
+   {
+      Int32 vv;
+      Int32 h = 1;
+      do h = 3 * h + 1; while (h <= 256);
+      do {
+         h = h / 3;
+         for (i = h; i <= 255; i++) {
+            vv = runningOrder[i];
+            j = i;
+            while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) {
+               runningOrder[j] = runningOrder[j-h];
+               j = j - h;
+               if (j <= (h - 1)) goto zero;
+            }
+            zero:
+            runningOrder[j] = vv;
+         }
+      } while (h != 1);
+   }
+
+   /*--
+      The main sorting loop.
+   --*/
+
+   numQSorted = 0;
+
+   for (i = 0; i <= 255; i++) {
+
+      /*--
+         Process big buckets, starting with the least full.
+         Basically this is a 3-step process in which we call
+         mainQSort3 to sort the small buckets [ss, j], but
+         also make a big effort to avoid the calls if we can.
+      --*/
+      ss = runningOrder[i];
+
+      /*--
+         Step 1:
+         Complete the big bucket [ss] by quicksorting
+         any unsorted small buckets [ss, j], for j != ss.  
+         Hopefully previous pointer-scanning phases have already
+         completed many of the small buckets [ss, j], so
+         we don't have to sort them at all.
+      --*/
+      for (j = 0; j <= 255; j++) {
+         if (j != ss) {
+            sb = (ss << 8) + j;
+            if ( ! (ftab[sb] & SETMASK) ) {
+               Int32 lo = ftab[sb]   & CLEARMASK;
+               Int32 hi = (ftab[sb+1] & CLEARMASK) - 1;
+               if (hi > lo) {
+                  if (verb >= 4)
+                     VPrintf4 ( "        qsort [0x%x, 0x%x]   "
+                                "done %d   this %d\n",
+                                ss, j, numQSorted, hi - lo + 1 );
+                  mainQSort3 ( 
+                     ptr, block, quadrant, nblock, 
+                     lo, hi, BZ_N_RADIX, budget 
+                  );   
+                  numQSorted += (hi - lo + 1);
+                  if (*budget < 0) return;
+               }
+            }
+            ftab[sb] |= SETMASK;
+         }
+      }
+
+      AssertH ( !bigDone[ss], 1006 );
+
+      /*--
+         Step 2:
+         Now scan this big bucket [ss] so as to synthesise the
+         sorted order for small buckets [t, ss] for all t,
+         including, magically, the bucket [ss,ss] too.
+         This will avoid doing Real Work in subsequent Step 1's.
+      --*/
+      {
+         for (j = 0; j <= 255; j++) {
+            copyStart[j] =  ftab[(j << 8) + ss]     & CLEARMASK;
+            copyEnd  [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1;
+         }
+         for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) {
+            k = ptr[j]-1; if (k < 0) k += nblock;
+            c1 = block[k];
+            if (!bigDone[c1])
+               ptr[ copyStart[c1]++ ] = k;
+         }
+         for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) {
+            k = ptr[j]-1; if (k < 0) k += nblock;
+            c1 = block[k];
+            if (!bigDone[c1]) 
+               ptr[ copyEnd[c1]-- ] = k;
+         }
+      }
+
+      AssertH ( (copyStart[ss]-1 == copyEnd[ss])
+                || 
+                /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1.
+                   Necessity for this case is demonstrated by compressing 
+                   a sequence of approximately 48.5 million of character 
+                   251; 1.0.0/1.0.1 will then die here. */
+                (copyStart[ss] == 0 && copyEnd[ss] == nblock-1),
+                1007 )
+
+      for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK;
+
+      /*--
+         Step 3:
+         The [ss] big bucket is now done.  Record this fact,
+         and update the quadrant descriptors.  Remember to
+         update quadrants in the overshoot area too, if
+         necessary.  The "if (i < 255)" test merely skips
+         this updating for the last bucket processed, since
+         updating for the last bucket is pointless.
+
+         The quadrant array provides a way to incrementally
+         cache sort orderings, as they appear, so as to 
+         make subsequent comparisons in fullGtU() complete
+         faster.  For repetitive blocks this makes a big
+         difference (but not big enough to be able to avoid
+         the fallback sorting mechanism, exponential radix sort).
+
+         The precise meaning is: at all times:
+
+            for 0 <= i < nblock and 0 <= j <= nblock
+
+            if block[i] != block[j], 
+
+               then the relative values of quadrant[i] and 
+                    quadrant[j] are meaningless.
+
+               else {
+                  if quadrant[i] < quadrant[j]
+                     then the string starting at i lexicographically
+                     precedes the string starting at j
+
+                  else if quadrant[i] > quadrant[j]
+                     then the string starting at j lexicographically
+                     precedes the string starting at i
+
+                  else
+                     the relative ordering of the strings starting
+                     at i and j has not yet been determined.
+               }
+      --*/
+      bigDone[ss] = True;
+
+      if (i < 255) {
+         Int32 bbStart  = ftab[ss << 8] & CLEARMASK;
+         Int32 bbSize   = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart;
+         Int32 shifts   = 0;
+
+         while ((bbSize >> shifts) > 65534) shifts++;
+
+         for (j = bbSize-1; j >= 0; j--) {
+            Int32 a2update     = ptr[bbStart + j];
+            UInt16 qVal        = (UInt16)(j >> shifts);
+            quadrant[a2update] = qVal;
+            if (a2update < BZ_N_OVERSHOOT)
+               quadrant[a2update + nblock] = qVal;
+         }
+         AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 );
+      }
+
+   }
+
+   if (verb >= 4)
+      VPrintf3 ( "        %d pointers, %d sorted, %d scanned\n",
+                 nblock, numQSorted, nblock - numQSorted );
+}
+
+#undef BIGFREQ
+#undef SETMASK
+#undef CLEARMASK
+
+
+/*---------------------------------------------*/
+/* Pre:
+      nblock > 0
+      arr2 exists for [0 .. nblock-1 +N_OVERSHOOT]
+      ((UChar*)arr2)  [0 .. nblock-1] holds block
+      arr1 exists for [0 .. nblock-1]
+
+   Post:
+      ((UChar*)arr2) [0 .. nblock-1] holds block
+      All other areas of block destroyed
+      ftab [ 0 .. 65536 ] destroyed
+      arr1 [0 .. nblock-1] holds sorted order
+*/
+void BZ2_blockSort ( EState* s )
+{
+   UInt32* ptr    = s->ptr; 
+   UChar*  block  = s->block;
+   UInt32* ftab   = s->ftab;
+   Int32   nblock = s->nblock;
+   Int32   verb   = s->verbosity;
+   Int32   wfact  = s->workFactor;
+   UInt16* quadrant;
+   Int32   budget;
+   Int32   budgetInit;
+   Int32   i;
+
+   if (nblock < 10000) {
+      fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
+   } else {
+      /* Calculate the location for quadrant, remembering to get
+         the alignment right.  Assumes that &(block[0]) is at least
+         2-byte aligned -- this should be ok since block is really
+         the first section of arr2.
+      */
+      i = nblock+BZ_N_OVERSHOOT;
+      if (i & 1) i++;
+      quadrant = (UInt16*)(&(block[i]));
+
+      /* (wfact-1) / 3 puts the default-factor-30
+         transition point at very roughly the same place as 
+         with v0.1 and v0.9.0.  
+         Not that it particularly matters any more, since the
+         resulting compressed stream is now the same regardless
+         of whether or not we use the main sort or fallback sort.
+      */
+      if (wfact < 1  ) wfact = 1;
+      if (wfact > 100) wfact = 100;
+      budgetInit = nblock * ((wfact-1) / 3);
+      budget = budgetInit;
+
+      mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget );
+      if (verb >= 3) 
+         VPrintf3 ( "      %d work, %d block, ratio %5.2f\n",
+                    budgetInit - budget,
+                    nblock, 
+                    (float)(budgetInit - budget) /
+                    (float)(nblock==0 ? 1 : nblock) ); 
+      if (budget < 0) {
+         if (verb >= 2) 
+            VPrintf0 ( "    too repetitive; using fallback"
+                       " sorting algorithm\n" );
+         fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb );
+      }
+   }
+
+   s->origPtr = -1;
+   for (i = 0; i < s->nblock; i++)
+      if (ptr[i] == 0)
+         { s->origPtr = i; break; };
+
+   AssertH( s->origPtr != -1, 1003 );
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                       blocksort.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/project/jni/bzip2/bzlib.c b/project/jni/bzip2/bzlib.c
new file mode 100644
index 000000000..bd358a793
--- /dev/null
+++ b/project/jni/bzip2/bzlib.c
@@ -0,0 +1,1572 @@
+
+/*-------------------------------------------------------------*/
+/*--- Library top-level functions.                          ---*/
+/*---                                               bzlib.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+/* CHANGES
+   0.9.0    -- original version.
+   0.9.0a/b -- no changes in this file.
+   0.9.0c   -- made zero-length BZ_FLUSH work correctly in bzCompress().
+     fixed bzWrite/bzRead to ignore zero-length requests.
+     fixed bzread to correctly handle read requests after EOF.
+     wrong parameter order in call to bzDecompressInit in
+     bzBuffToBuffDecompress.  Fixed.
+*/
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+/*--- Compression stuff                           ---*/
+/*---------------------------------------------------*/
+
+
+/*---------------------------------------------------*/
+#ifndef BZ_NO_STDIO
+void BZ2_bz__AssertH__fail ( int errcode )
+{
+   fprintf(stderr, 
+      "\n\nbzip2/libbzip2: internal error number %d.\n"
+      "This is a bug in bzip2/libbzip2, %s.\n"
+      "Please report it to me at: jseward@bzip.org.  If this happened\n"
+      "when you were using some program which uses libbzip2 as a\n"
+      "component, you should also report this bug to the author(s)\n"
+      "of that program.  Please make an effort to report this bug;\n"
+      "timely and accurate bug reports eventually lead to higher\n"
+      "quality software.  Thanks.  Julian Seward, 10 December 2007.\n\n",
+      errcode,
+      BZ2_bzlibVersion()
+   );
+
+   if (errcode == 1007) {
+   fprintf(stderr,
+      "\n*** A special note about internal error number 1007 ***\n"
+      "\n"
+      "Experience suggests that a common cause of i.e. 1007\n"
+      "is unreliable memory or other hardware.  The 1007 assertion\n"
+      "just happens to cross-check the results of huge numbers of\n"
+      "memory reads/writes, and so acts (unintendedly) as a stress\n"
+      "test of your memory system.\n"
+      "\n"
+      "I suggest the following: try compressing the file again,\n"
+      "possibly monitoring progress in detail with the -vv flag.\n"
+      "\n"
+      "* If the error cannot be reproduced, and/or happens at different\n"
+      "  points in compression, you may have a flaky memory system.\n"
+      "  Try a memory-test program.  I have used Memtest86\n"
+      "  (www.memtest86.com).  At the time of writing it is free (GPLd).\n"
+      "  Memtest86 tests memory much more thorougly than your BIOSs\n"
+      "  power-on test, and may find failures that the BIOS doesn't.\n"
+      "\n"
+      "* If the error can be repeatably reproduced, this is a bug in\n"
+      "  bzip2, and I would very much like to hear about it.  Please\n"
+      "  let me know, and, ideally, save a copy of the file causing the\n"
+      "  problem -- without which I will be unable to investigate it.\n"
+      "\n"
+   );
+   }
+
+   exit(3);
+}
+#endif
+
+
+/*---------------------------------------------------*/
+static
+int bz_config_ok ( void )
+{
+   if (sizeof(int)   != 4) return 0;
+   if (sizeof(short) != 2) return 0;
+   if (sizeof(char)  != 1) return 0;
+   return 1;
+}
+
+
+/*---------------------------------------------------*/
+static
+void* default_bzalloc ( void* opaque, Int32 items, Int32 size )
+{
+   void* v = malloc ( items * size );
+   return v;
+}
+
+static
+void default_bzfree ( void* opaque, void* addr )
+{
+   if (addr != NULL) free ( addr );
+}
+
+
+/*---------------------------------------------------*/
+static
+void prepare_new_block ( EState* s )
+{
+   Int32 i;
+   s->nblock = 0;
+   s->numZ = 0;
+   s->state_out_pos = 0;
+   BZ_INITIALISE_CRC ( s->blockCRC );
+   for (i = 0; i < 256; i++) s->inUse[i] = False;
+   s->blockNo++;
+}
+
+
+/*---------------------------------------------------*/
+static
+void init_RL ( EState* s )
+{
+   s->state_in_ch  = 256;
+   s->state_in_len = 0;
+}
+
+
+static
+Bool isempty_RL ( EState* s )
+{
+   if (s->state_in_ch < 256 && s->state_in_len > 0)
+      return False; else
+      return True;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompressInit) 
+                    ( bz_stream* strm, 
+                     int        blockSize100k,
+                     int        verbosity,
+                     int        workFactor )
+{
+   Int32   n;
+   EState* s;
+
+   if (!bz_config_ok()) return BZ_CONFIG_ERROR;
+
+   if (strm == NULL || 
+       blockSize100k < 1 || blockSize100k > 9 ||
+       workFactor < 0 || workFactor > 250)
+     return BZ_PARAM_ERROR;
+
+   if (workFactor == 0) workFactor = 30;
+   if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
+   if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
+
+   s = BZALLOC( sizeof(EState) );
+   if (s == NULL) return BZ_MEM_ERROR;
+   s->strm = strm;
+
+   s->arr1 = NULL;
+   s->arr2 = NULL;
+   s->ftab = NULL;
+
+   n       = 100000 * blockSize100k;
+   s->arr1 = BZALLOC( n                  * sizeof(UInt32) );
+   s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) );
+   s->ftab = BZALLOC( 65537              * sizeof(UInt32) );
+
+   if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) {
+      if (s->arr1 != NULL) BZFREE(s->arr1);
+      if (s->arr2 != NULL) BZFREE(s->arr2);
+      if (s->ftab != NULL) BZFREE(s->ftab);
+      if (s       != NULL) BZFREE(s);
+      return BZ_MEM_ERROR;
+   }
+
+   s->blockNo           = 0;
+   s->state             = BZ_S_INPUT;
+   s->mode              = BZ_M_RUNNING;
+   s->combinedCRC       = 0;
+   s->blockSize100k     = blockSize100k;
+   s->nblockMAX         = 100000 * blockSize100k - 19;
+   s->verbosity         = verbosity;
+   s->workFactor        = workFactor;
+
+   s->block             = (UChar*)s->arr2;
+   s->mtfv              = (UInt16*)s->arr1;
+   s->zbits             = NULL;
+   s->ptr               = (UInt32*)s->arr1;
+
+   strm->state          = s;
+   strm->total_in_lo32  = 0;
+   strm->total_in_hi32  = 0;
+   strm->total_out_lo32 = 0;
+   strm->total_out_hi32 = 0;
+   init_RL ( s );
+   prepare_new_block ( s );
+   return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+static
+void add_pair_to_block ( EState* s )
+{
+   Int32 i;
+   UChar ch = (UChar)(s->state_in_ch);
+   for (i = 0; i < s->state_in_len; i++) {
+      BZ_UPDATE_CRC( s->blockCRC, ch );
+   }
+   s->inUse[s->state_in_ch] = True;
+   switch (s->state_in_len) {
+      case 1:
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         break;
+      case 2:
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         break;
+      case 3:
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         break;
+      default:
+         s->inUse[s->state_in_len-4] = True;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = (UChar)ch; s->nblock++;
+         s->block[s->nblock] = ((UChar)(s->state_in_len-4));
+         s->nblock++;
+         break;
+   }
+}
+
+
+/*---------------------------------------------------*/
+static
+void flush_RL ( EState* s )
+{
+   if (s->state_in_ch < 256) add_pair_to_block ( s );
+   init_RL ( s );
+}
+
+
+/*---------------------------------------------------*/
+#define ADD_CHAR_TO_BLOCK(zs,zchh0)               \
+{                                                 \
+   UInt32 zchh = (UInt32)(zchh0);                 \
+   /*-- fast track the common case --*/           \
+   if (zchh != zs->state_in_ch &&                 \
+       zs->state_in_len == 1) {                   \
+      UChar ch = (UChar)(zs->state_in_ch);        \
+      BZ_UPDATE_CRC( zs->blockCRC, ch );          \
+      zs->inUse[zs->state_in_ch] = True;          \
+      zs->block[zs->nblock] = (UChar)ch;          \
+      zs->nblock++;                               \
+      zs->state_in_ch = zchh;                     \
+   }                                              \
+   else                                           \
+   /*-- general, uncommon cases --*/              \
+   if (zchh != zs->state_in_ch ||                 \
+      zs->state_in_len == 255) {                  \
+      if (zs->state_in_ch < 256)                  \
+         add_pair_to_block ( zs );                \
+      zs->state_in_ch = zchh;                     \
+      zs->state_in_len = 1;                       \
+   } else {                                       \
+      zs->state_in_len++;                         \
+   }                                              \
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool copy_input_until_stop ( EState* s )
+{
+   Bool progress_in = False;
+
+   if (s->mode == BZ_M_RUNNING) {
+
+      /*-- fast track the common case --*/
+      while (True) {
+         /*-- block full? --*/
+         if (s->nblock >= s->nblockMAX) break;
+         /*-- no input? --*/
+         if (s->strm->avail_in == 0) break;
+         progress_in = True;
+         ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); 
+         s->strm->next_in++;
+         s->strm->avail_in--;
+         s->strm->total_in_lo32++;
+         if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
+      }
+
+   } else {
+
+      /*-- general, uncommon case --*/
+      while (True) {
+         /*-- block full? --*/
+         if (s->nblock >= s->nblockMAX) break;
+         /*-- no input? --*/
+         if (s->strm->avail_in == 0) break;
+         /*-- flush/finish end? --*/
+         if (s->avail_in_expect == 0) break;
+         progress_in = True;
+         ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); 
+         s->strm->next_in++;
+         s->strm->avail_in--;
+         s->strm->total_in_lo32++;
+         if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
+         s->avail_in_expect--;
+      }
+   }
+   return progress_in;
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool copy_output_until_stop ( EState* s )
+{
+   Bool progress_out = False;
+
+   while (True) {
+
+      /*-- no output space? --*/
+      if (s->strm->avail_out == 0) break;
+
+      /*-- block done? --*/
+      if (s->state_out_pos >= s->numZ) break;
+
+      progress_out = True;
+      *(s->strm->next_out) = s->zbits[s->state_out_pos];
+      s->state_out_pos++;
+      s->strm->avail_out--;
+      s->strm->next_out++;
+      s->strm->total_out_lo32++;
+      if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+   }
+
+   return progress_out;
+}
+
+
+/*---------------------------------------------------*/
+static
+Bool handle_compress ( bz_stream* strm )
+{
+   Bool progress_in  = False;
+   Bool progress_out = False;
+   EState* s = strm->state;
+   
+   while (True) {
+
+      if (s->state == BZ_S_OUTPUT) {
+         progress_out |= copy_output_until_stop ( s );
+         if (s->state_out_pos < s->numZ) break;
+         if (s->mode == BZ_M_FINISHING && 
+             s->avail_in_expect == 0 &&
+             isempty_RL(s)) break;
+         prepare_new_block ( s );
+         s->state = BZ_S_INPUT;
+         if (s->mode == BZ_M_FLUSHING && 
+             s->avail_in_expect == 0 &&
+             isempty_RL(s)) break;
+      }
+
+      if (s->state == BZ_S_INPUT) {
+         progress_in |= copy_input_until_stop ( s );
+         if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
+            flush_RL ( s );
+            BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) );
+            s->state = BZ_S_OUTPUT;
+         }
+         else
+         if (s->nblock >= s->nblockMAX) {
+            BZ2_compressBlock ( s, False );
+            s->state = BZ_S_OUTPUT;
+         }
+         else
+         if (s->strm->avail_in == 0) {
+            break;
+         }
+      }
+
+   }
+
+   return progress_in || progress_out;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action )
+{
+   Bool progress;
+   EState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   preswitch:
+   switch (s->mode) {
+
+      case BZ_M_IDLE:
+         return BZ_SEQUENCE_ERROR;
+
+      case BZ_M_RUNNING:
+         if (action == BZ_RUN) {
+            progress = handle_compress ( strm );
+            return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;
+         } 
+         else
+	 if (action == BZ_FLUSH) {
+            s->avail_in_expect = strm->avail_in;
+            s->mode = BZ_M_FLUSHING;
+            goto preswitch;
+         }
+         else
+         if (action == BZ_FINISH) {
+            s->avail_in_expect = strm->avail_in;
+            s->mode = BZ_M_FINISHING;
+            goto preswitch;
+         }
+         else 
+            return BZ_PARAM_ERROR;
+
+      case BZ_M_FLUSHING:
+         if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR;
+         if (s->avail_in_expect != s->strm->avail_in) 
+            return BZ_SEQUENCE_ERROR;
+         progress = handle_compress ( strm );
+         if (s->avail_in_expect > 0 || !isempty_RL(s) ||
+             s->state_out_pos < s->numZ) return BZ_FLUSH_OK;
+         s->mode = BZ_M_RUNNING;
+         return BZ_RUN_OK;
+
+      case BZ_M_FINISHING:
+         if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR;
+         if (s->avail_in_expect != s->strm->avail_in) 
+            return BZ_SEQUENCE_ERROR;
+         progress = handle_compress ( strm );
+         if (!progress) return BZ_SEQUENCE_ERROR;
+         if (s->avail_in_expect > 0 || !isempty_RL(s) ||
+             s->state_out_pos < s->numZ) return BZ_FINISH_OK;
+         s->mode = BZ_M_IDLE;
+         return BZ_STREAM_END;
+   }
+   return BZ_OK; /*--not reached--*/
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzCompressEnd)  ( bz_stream *strm )
+{
+   EState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   if (s->arr1 != NULL) BZFREE(s->arr1);
+   if (s->arr2 != NULL) BZFREE(s->arr2);
+   if (s->ftab != NULL) BZFREE(s->ftab);
+   BZFREE(strm->state);
+
+   strm->state = NULL;   
+
+   return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+/*--- Decompression stuff                         ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompressInit) 
+                     ( bz_stream* strm, 
+                       int        verbosity,
+                       int        small )
+{
+   DState* s;
+
+   if (!bz_config_ok()) return BZ_CONFIG_ERROR;
+
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   if (small != 0 && small != 1) return BZ_PARAM_ERROR;
+   if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR;
+
+   if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
+   if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
+
+   s = BZALLOC( sizeof(DState) );
+   if (s == NULL) return BZ_MEM_ERROR;
+   s->strm                  = strm;
+   strm->state              = s;
+   s->state                 = BZ_X_MAGIC_1;
+   s->bsLive                = 0;
+   s->bsBuff                = 0;
+   s->calculatedCombinedCRC = 0;
+   strm->total_in_lo32      = 0;
+   strm->total_in_hi32      = 0;
+   strm->total_out_lo32     = 0;
+   strm->total_out_hi32     = 0;
+   s->smallDecompress       = (Bool)small;
+   s->ll4                   = NULL;
+   s->ll16                  = NULL;
+   s->tt                    = NULL;
+   s->currBlockNo           = 0;
+   s->verbosity             = verbosity;
+
+   return BZ_OK;
+}
+
+
+/*---------------------------------------------------*/
+/* Return  True iff data corruption is discovered.
+   Returns False if there is no problem.
+*/
+static
+Bool unRLE_obuf_to_output_FAST ( DState* s )
+{
+   UChar k1;
+
+   if (s->blockRandomised) {
+
+      while (True) {
+         /* try to finish existing run */
+         while (True) {
+            if (s->strm->avail_out == 0) return False;
+            if (s->state_out_len == 0) break;
+            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+            s->state_out_len--;
+            s->strm->next_out++;
+            s->strm->avail_out--;
+            s->strm->total_out_lo32++;
+            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+         }
+
+         /* can a new run be started? */
+         if (s->nblock_used == s->save_nblock+1) return False;
+               
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
+   
+         s->state_out_len = 1;
+         s->state_out_ch = s->k0;
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 2;
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 3;
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         s->state_out_len = ((Int32)k1) + 4;
+         BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; 
+         s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
+      }
+
+   } else {
+
+      /* restore */
+      UInt32        c_calculatedBlockCRC = s->calculatedBlockCRC;
+      UChar         c_state_out_ch       = s->state_out_ch;
+      Int32         c_state_out_len      = s->state_out_len;
+      Int32         c_nblock_used        = s->nblock_used;
+      Int32         c_k0                 = s->k0;
+      UInt32*       c_tt                 = s->tt;
+      UInt32        c_tPos               = s->tPos;
+      char*         cs_next_out          = s->strm->next_out;
+      unsigned int  cs_avail_out         = s->strm->avail_out;
+      Int32         ro_blockSize100k     = s->blockSize100k;
+      /* end restore */
+
+      UInt32       avail_out_INIT = cs_avail_out;
+      Int32        s_save_nblockPP = s->save_nblock+1;
+      unsigned int total_out_lo32_old;
+
+      while (True) {
+
+         /* try to finish existing run */
+         if (c_state_out_len > 0) {
+            while (True) {
+               if (cs_avail_out == 0) goto return_notr;
+               if (c_state_out_len == 1) break;
+               *( (UChar*)(cs_next_out) ) = c_state_out_ch;
+               BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
+               c_state_out_len--;
+               cs_next_out++;
+               cs_avail_out--;
+            }
+            s_state_out_len_eq_one:
+            {
+               if (cs_avail_out == 0) { 
+                  c_state_out_len = 1; goto return_notr;
+               };
+               *( (UChar*)(cs_next_out) ) = c_state_out_ch;
+               BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
+               cs_next_out++;
+               cs_avail_out--;
+            }
+         }   
+         /* Only caused by corrupt data stream? */
+         if (c_nblock_used > s_save_nblockPP)
+            return True;
+
+         /* can a new run be started? */
+         if (c_nblock_used == s_save_nblockPP) {
+            c_state_out_len = 0; goto return_notr;
+         };   
+         c_state_out_ch = c_k0;
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         if (k1 != c_k0) { 
+            c_k0 = k1; goto s_state_out_len_eq_one; 
+         };
+         if (c_nblock_used == s_save_nblockPP) 
+            goto s_state_out_len_eq_one;
+   
+         c_state_out_len = 2;
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         if (c_nblock_used == s_save_nblockPP) continue;
+         if (k1 != c_k0) { c_k0 = k1; continue; };
+   
+         c_state_out_len = 3;
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         if (c_nblock_used == s_save_nblockPP) continue;
+         if (k1 != c_k0) { c_k0 = k1; continue; };
+   
+         BZ_GET_FAST_C(k1); c_nblock_used++;
+         c_state_out_len = ((Int32)k1) + 4;
+         BZ_GET_FAST_C(c_k0); c_nblock_used++;
+      }
+
+      return_notr:
+      total_out_lo32_old = s->strm->total_out_lo32;
+      s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
+      if (s->strm->total_out_lo32 < total_out_lo32_old)
+         s->strm->total_out_hi32++;
+
+      /* save */
+      s->calculatedBlockCRC = c_calculatedBlockCRC;
+      s->state_out_ch       = c_state_out_ch;
+      s->state_out_len      = c_state_out_len;
+      s->nblock_used        = c_nblock_used;
+      s->k0                 = c_k0;
+      s->tt                 = c_tt;
+      s->tPos               = c_tPos;
+      s->strm->next_out     = cs_next_out;
+      s->strm->avail_out    = cs_avail_out;
+      /* end save */
+   }
+   return False;
+}
+
+
+
+/*---------------------------------------------------*/
+__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab )
+{
+   Int32 nb, na, mid;
+   nb = 0;
+   na = 256;
+   do {
+      mid = (nb + na) >> 1;
+      if (indx >= cftab[mid]) nb = mid; else na = mid;
+   }
+   while (na - nb != 1);
+   return nb;
+}
+
+
+/*---------------------------------------------------*/
+/* Return  True iff data corruption is discovered.
+   Returns False if there is no problem.
+*/
+static
+Bool unRLE_obuf_to_output_SMALL ( DState* s )
+{
+   UChar k1;
+
+   if (s->blockRandomised) {
+
+      while (True) {
+         /* try to finish existing run */
+         while (True) {
+            if (s->strm->avail_out == 0) return False;
+            if (s->state_out_len == 0) break;
+            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+            s->state_out_len--;
+            s->strm->next_out++;
+            s->strm->avail_out--;
+            s->strm->total_out_lo32++;
+            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+         }
+   
+         /* can a new run be started? */
+         if (s->nblock_used == s->save_nblock+1) return False;
+
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
+   
+         s->state_out_len = 1;
+         s->state_out_ch = s->k0;
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 2;
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 3;
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
+         k1 ^= BZ_RAND_MASK; s->nblock_used++;
+         s->state_out_len = ((Int32)k1) + 4;
+         BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; 
+         s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
+      }
+
+   } else {
+
+      while (True) {
+         /* try to finish existing run */
+         while (True) {
+            if (s->strm->avail_out == 0) return False;
+            if (s->state_out_len == 0) break;
+            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
+            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
+            s->state_out_len--;
+            s->strm->next_out++;
+            s->strm->avail_out--;
+            s->strm->total_out_lo32++;
+            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
+         }
+   
+         /* can a new run be started? */
+         if (s->nblock_used == s->save_nblock+1) return False;
+
+         /* Only caused by corrupt data stream? */
+         if (s->nblock_used > s->save_nblock+1)
+            return True;
+   
+         s->state_out_len = 1;
+         s->state_out_ch = s->k0;
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 2;
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         s->state_out_len = 3;
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         if (s->nblock_used == s->save_nblock+1) continue;
+         if (k1 != s->k0) { s->k0 = k1; continue; };
+   
+         BZ_GET_SMALL(k1); s->nblock_used++;
+         s->state_out_len = ((Int32)k1) + 4;
+         BZ_GET_SMALL(s->k0); s->nblock_used++;
+      }
+
+   }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
+{
+   Bool    corrupt;
+   DState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   while (True) {
+      if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
+      if (s->state == BZ_X_OUTPUT) {
+         if (s->smallDecompress)
+            corrupt = unRLE_obuf_to_output_SMALL ( s ); else
+            corrupt = unRLE_obuf_to_output_FAST  ( s );
+         if (corrupt) return BZ_DATA_ERROR;
+         if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
+            BZ_FINALISE_CRC ( s->calculatedBlockCRC );
+            if (s->verbosity >= 3) 
+               VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, 
+                          s->calculatedBlockCRC );
+            if (s->verbosity >= 2) VPrintf0 ( "]" );
+            if (s->calculatedBlockCRC != s->storedBlockCRC)
+               return BZ_DATA_ERROR;
+            s->calculatedCombinedCRC 
+               = (s->calculatedCombinedCRC << 1) | 
+                    (s->calculatedCombinedCRC >> 31);
+            s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
+            s->state = BZ_X_BLKHDR_1;
+         } else {
+            return BZ_OK;
+         }
+      }
+      if (s->state >= BZ_X_MAGIC_1) {
+         Int32 r = BZ2_decompress ( s );
+         if (r == BZ_STREAM_END) {
+            if (s->verbosity >= 3)
+               VPrintf2 ( "\n    combined CRCs: stored = 0x%08x, computed = 0x%08x", 
+                          s->storedCombinedCRC, s->calculatedCombinedCRC );
+            if (s->calculatedCombinedCRC != s->storedCombinedCRC)
+               return BZ_DATA_ERROR;
+            return r;
+         }
+         if (s->state != BZ_X_OUTPUT) return r;
+      }
+   }
+
+   AssertH ( 0, 6001 );
+
+   return 0;  /*NOTREACHED*/
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzDecompressEnd)  ( bz_stream *strm )
+{
+   DState* s;
+   if (strm == NULL) return BZ_PARAM_ERROR;
+   s = strm->state;
+   if (s == NULL) return BZ_PARAM_ERROR;
+   if (s->strm != strm) return BZ_PARAM_ERROR;
+
+   if (s->tt   != NULL) BZFREE(s->tt);
+   if (s->ll16 != NULL) BZFREE(s->ll16);
+   if (s->ll4  != NULL) BZFREE(s->ll4);
+
+   BZFREE(strm->state);
+   strm->state = NULL;
+
+   return BZ_OK;
+}
+
+
+#ifndef BZ_NO_STDIO
+/*---------------------------------------------------*/
+/*--- File I/O stuff                              ---*/
+/*---------------------------------------------------*/
+
+#define BZ_SETERR(eee)                    \
+{                                         \
+   if (bzerror != NULL) *bzerror = eee;   \
+   if (bzf != NULL) bzf->lastErr = eee;   \
+}
+
+typedef 
+   struct {
+      FILE*     handle;
+      Char      buf[BZ_MAX_UNUSED];
+      Int32     bufN;
+      Bool      writing;
+      bz_stream strm;
+      Int32     lastErr;
+      Bool      initialisedOk;
+   }
+   bzFile;
+
+
+/*---------------------------------------------*/
+static Bool myfeof ( FILE* f )
+{
+   Int32 c = fgetc ( f );
+   if (c == EOF) return True;
+   ungetc ( c, f );
+   return False;
+}
+
+
+/*---------------------------------------------------*/
+BZFILE* BZ_API(BZ2_bzWriteOpen) 
+                    ( int*  bzerror,      
+                      FILE* f, 
+                      int   blockSize100k, 
+                      int   verbosity,
+                      int   workFactor )
+{
+   Int32   ret;
+   bzFile* bzf = NULL;
+
+   BZ_SETERR(BZ_OK);
+
+   if (f == NULL ||
+       (blockSize100k < 1 || blockSize100k > 9) ||
+       (workFactor < 0 || workFactor > 250) ||
+       (verbosity < 0 || verbosity > 4))
+      { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
+
+   if (ferror(f))
+      { BZ_SETERR(BZ_IO_ERROR); return NULL; };
+
+   bzf = malloc ( sizeof(bzFile) );
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
+
+   BZ_SETERR(BZ_OK);
+   bzf->initialisedOk = False;
+   bzf->bufN          = 0;
+   bzf->handle        = f;
+   bzf->writing       = True;
+   bzf->strm.bzalloc  = NULL;
+   bzf->strm.bzfree   = NULL;
+   bzf->strm.opaque   = NULL;
+
+   if (workFactor == 0) workFactor = 30;
+   ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, 
+                              verbosity, workFactor );
+   if (ret != BZ_OK)
+      { BZ_SETERR(ret); free(bzf); return NULL; };
+
+   bzf->strm.avail_in = 0;
+   bzf->initialisedOk = True;
+   return bzf;   
+}
+
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzWrite)
+             ( int*    bzerror, 
+               BZFILE* b, 
+               void*   buf, 
+               int     len )
+{
+   Int32 n, n2, ret;
+   bzFile* bzf = (bzFile*)b;
+
+   BZ_SETERR(BZ_OK);
+   if (bzf == NULL || buf == NULL || len < 0)
+      { BZ_SETERR(BZ_PARAM_ERROR); return; };
+   if (!(bzf->writing))
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+   if (ferror(bzf->handle))
+      { BZ_SETERR(BZ_IO_ERROR); return; };
+
+   if (len == 0)
+      { BZ_SETERR(BZ_OK); return; };
+
+   bzf->strm.avail_in = len;
+   bzf->strm.next_in  = buf;
+
+   while (True) {
+      bzf->strm.avail_out = BZ_MAX_UNUSED;
+      bzf->strm.next_out = bzf->buf;
+      ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN );
+      if (ret != BZ_RUN_OK)
+         { BZ_SETERR(ret); return; };
+
+      if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
+         n = BZ_MAX_UNUSED - bzf->strm.avail_out;
+         n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), 
+                       n, bzf->handle );
+         if (n != n2 || ferror(bzf->handle))
+            { BZ_SETERR(BZ_IO_ERROR); return; };
+      }
+
+      if (bzf->strm.avail_in == 0)
+         { BZ_SETERR(BZ_OK); return; };
+   }
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzWriteClose)
+                  ( int*          bzerror, 
+                    BZFILE*       b, 
+                    int           abandon,
+                    unsigned int* nbytes_in,
+                    unsigned int* nbytes_out )
+{
+   BZ2_bzWriteClose64 ( bzerror, b, abandon, 
+                        nbytes_in, NULL, nbytes_out, NULL );
+}
+
+
+void BZ_API(BZ2_bzWriteClose64)
+                  ( int*          bzerror, 
+                    BZFILE*       b, 
+                    int           abandon,
+                    unsigned int* nbytes_in_lo32,
+                    unsigned int* nbytes_in_hi32,
+                    unsigned int* nbytes_out_lo32,
+                    unsigned int* nbytes_out_hi32 )
+{
+   Int32   n, n2, ret;
+   bzFile* bzf = (bzFile*)b;
+
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_OK); return; };
+   if (!(bzf->writing))
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+   if (ferror(bzf->handle))
+      { BZ_SETERR(BZ_IO_ERROR); return; };
+
+   if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0;
+   if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0;
+   if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0;
+   if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0;
+
+   if ((!abandon) && bzf->lastErr == BZ_OK) {
+      while (True) {
+         bzf->strm.avail_out = BZ_MAX_UNUSED;
+         bzf->strm.next_out = bzf->buf;
+         ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH );
+         if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
+            { BZ_SETERR(ret); return; };
+
+         if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
+            n = BZ_MAX_UNUSED - bzf->strm.avail_out;
+            n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), 
+                          n, bzf->handle );
+            if (n != n2 || ferror(bzf->handle))
+               { BZ_SETERR(BZ_IO_ERROR); return; };
+         }
+
+         if (ret == BZ_STREAM_END) break;
+      }
+   }
+
+   if ( !abandon && !ferror ( bzf->handle ) ) {
+      fflush ( bzf->handle );
+      if (ferror(bzf->handle))
+         { BZ_SETERR(BZ_IO_ERROR); return; };
+   }
+
+   if (nbytes_in_lo32 != NULL)
+      *nbytes_in_lo32 = bzf->strm.total_in_lo32;
+   if (nbytes_in_hi32 != NULL)
+      *nbytes_in_hi32 = bzf->strm.total_in_hi32;
+   if (nbytes_out_lo32 != NULL)
+      *nbytes_out_lo32 = bzf->strm.total_out_lo32;
+   if (nbytes_out_hi32 != NULL)
+      *nbytes_out_hi32 = bzf->strm.total_out_hi32;
+
+   BZ_SETERR(BZ_OK);
+   BZ2_bzCompressEnd ( &(bzf->strm) );
+   free ( bzf );
+}
+
+
+/*---------------------------------------------------*/
+BZFILE* BZ_API(BZ2_bzReadOpen) 
+                   ( int*  bzerror, 
+                     FILE* f, 
+                     int   verbosity,
+                     int   small,
+                     void* unused,
+                     int   nUnused )
+{
+   bzFile* bzf = NULL;
+   int     ret;
+
+   BZ_SETERR(BZ_OK);
+
+   if (f == NULL || 
+       (small != 0 && small != 1) ||
+       (verbosity < 0 || verbosity > 4) ||
+       (unused == NULL && nUnused != 0) ||
+       (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)))
+      { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
+
+   if (ferror(f))
+      { BZ_SETERR(BZ_IO_ERROR); return NULL; };
+
+   bzf = malloc ( sizeof(bzFile) );
+   if (bzf == NULL) 
+      { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
+
+   BZ_SETERR(BZ_OK);
+
+   bzf->initialisedOk = False;
+   bzf->handle        = f;
+   bzf->bufN          = 0;
+   bzf->writing       = False;
+   bzf->strm.bzalloc  = NULL;
+   bzf->strm.bzfree   = NULL;
+   bzf->strm.opaque   = NULL;
+   
+   while (nUnused > 0) {
+      bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++;
+      unused = ((void*)( 1 + ((UChar*)(unused))  ));
+      nUnused--;
+   }
+
+   ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small );
+   if (ret != BZ_OK)
+      { BZ_SETERR(ret); free(bzf); return NULL; };
+
+   bzf->strm.avail_in = bzf->bufN;
+   bzf->strm.next_in  = bzf->buf;
+
+   bzf->initialisedOk = True;
+   return bzf;   
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b )
+{
+   bzFile* bzf = (bzFile*)b;
+
+   BZ_SETERR(BZ_OK);
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_OK); return; };
+
+   if (bzf->writing)
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+
+   if (bzf->initialisedOk)
+      (void)BZ2_bzDecompressEnd ( &(bzf->strm) );
+   free ( bzf );
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzRead) 
+           ( int*    bzerror, 
+             BZFILE* b, 
+             void*   buf, 
+             int     len )
+{
+   Int32   n, ret;
+   bzFile* bzf = (bzFile*)b;
+
+   BZ_SETERR(BZ_OK);
+
+   if (bzf == NULL || buf == NULL || len < 0)
+      { BZ_SETERR(BZ_PARAM_ERROR); return 0; };
+
+   if (bzf->writing)
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; };
+
+   if (len == 0)
+      { BZ_SETERR(BZ_OK); return 0; };
+
+   bzf->strm.avail_out = len;
+   bzf->strm.next_out = buf;
+
+   while (True) {
+
+      if (ferror(bzf->handle)) 
+         { BZ_SETERR(BZ_IO_ERROR); return 0; };
+
+      if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) {
+         n = fread ( bzf->buf, sizeof(UChar), 
+                     BZ_MAX_UNUSED, bzf->handle );
+         if (ferror(bzf->handle))
+            { BZ_SETERR(BZ_IO_ERROR); return 0; };
+         bzf->bufN = n;
+         bzf->strm.avail_in = bzf->bufN;
+         bzf->strm.next_in = bzf->buf;
+      }
+
+      ret = BZ2_bzDecompress ( &(bzf->strm) );
+
+      if (ret != BZ_OK && ret != BZ_STREAM_END)
+         { BZ_SETERR(ret); return 0; };
+
+      if (ret == BZ_OK && myfeof(bzf->handle) && 
+          bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0)
+         { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; };
+
+      if (ret == BZ_STREAM_END)
+         { BZ_SETERR(BZ_STREAM_END);
+           return len - bzf->strm.avail_out; };
+      if (bzf->strm.avail_out == 0)
+         { BZ_SETERR(BZ_OK); return len; };
+      
+   }
+
+   return 0; /*not reached*/
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzReadGetUnused) 
+                     ( int*    bzerror, 
+                       BZFILE* b, 
+                       void**  unused, 
+                       int*    nUnused )
+{
+   bzFile* bzf = (bzFile*)b;
+   if (bzf == NULL)
+      { BZ_SETERR(BZ_PARAM_ERROR); return; };
+   if (bzf->lastErr != BZ_STREAM_END)
+      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
+   if (unused == NULL || nUnused == NULL)
+      { BZ_SETERR(BZ_PARAM_ERROR); return; };
+
+   BZ_SETERR(BZ_OK);
+   *nUnused = bzf->strm.avail_in;
+   *unused = bzf->strm.next_in;
+}
+#endif
+
+
+/*---------------------------------------------------*/
+/*--- Misc convenience stuff                      ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzBuffToBuffCompress) 
+                         ( char*         dest, 
+                           unsigned int* destLen,
+                           char*         source, 
+                           unsigned int  sourceLen,
+                           int           blockSize100k, 
+                           int           verbosity, 
+                           int           workFactor )
+{
+   bz_stream strm;
+   int ret;
+
+   if (dest == NULL || destLen == NULL || 
+       source == NULL ||
+       blockSize100k < 1 || blockSize100k > 9 ||
+       verbosity < 0 || verbosity > 4 ||
+       workFactor < 0 || workFactor > 250) 
+      return BZ_PARAM_ERROR;
+
+   if (workFactor == 0) workFactor = 30;
+   strm.bzalloc = NULL;
+   strm.bzfree = NULL;
+   strm.opaque = NULL;
+   ret = BZ2_bzCompressInit ( &strm, blockSize100k, 
+                              verbosity, workFactor );
+   if (ret != BZ_OK) return ret;
+
+   strm.next_in = source;
+   strm.next_out = dest;
+   strm.avail_in = sourceLen;
+   strm.avail_out = *destLen;
+
+   ret = BZ2_bzCompress ( &strm, BZ_FINISH );
+   if (ret == BZ_FINISH_OK) goto output_overflow;
+   if (ret != BZ_STREAM_END) goto errhandler;
+
+   /* normal termination */
+   *destLen -= strm.avail_out;   
+   BZ2_bzCompressEnd ( &strm );
+   return BZ_OK;
+
+   output_overflow:
+   BZ2_bzCompressEnd ( &strm );
+   return BZ_OUTBUFF_FULL;
+
+   errhandler:
+   BZ2_bzCompressEnd ( &strm );
+   return ret;
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzBuffToBuffDecompress) 
+                           ( char*         dest, 
+                             unsigned int* destLen,
+                             char*         source, 
+                             unsigned int  sourceLen,
+                             int           small,
+                             int           verbosity )
+{
+   bz_stream strm;
+   int ret;
+
+   if (dest == NULL || destLen == NULL || 
+       source == NULL ||
+       (small != 0 && small != 1) ||
+       verbosity < 0 || verbosity > 4) 
+          return BZ_PARAM_ERROR;
+
+   strm.bzalloc = NULL;
+   strm.bzfree = NULL;
+   strm.opaque = NULL;
+   ret = BZ2_bzDecompressInit ( &strm, verbosity, small );
+   if (ret != BZ_OK) return ret;
+
+   strm.next_in = source;
+   strm.next_out = dest;
+   strm.avail_in = sourceLen;
+   strm.avail_out = *destLen;
+
+   ret = BZ2_bzDecompress ( &strm );
+   if (ret == BZ_OK) goto output_overflow_or_eof;
+   if (ret != BZ_STREAM_END) goto errhandler;
+
+   /* normal termination */
+   *destLen -= strm.avail_out;
+   BZ2_bzDecompressEnd ( &strm );
+   return BZ_OK;
+
+   output_overflow_or_eof:
+   if (strm.avail_out > 0) {
+      BZ2_bzDecompressEnd ( &strm );
+      return BZ_UNEXPECTED_EOF;
+   } else {
+      BZ2_bzDecompressEnd ( &strm );
+      return BZ_OUTBUFF_FULL;
+   };      
+
+   errhandler:
+   BZ2_bzDecompressEnd ( &strm );
+   return ret; 
+}
+
+
+/*---------------------------------------------------*/
+/*--
+   Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
+   to support better zlib compatibility.
+   This code is not _officially_ part of libbzip2 (yet);
+   I haven't tested it, documented it, or considered the
+   threading-safeness of it.
+   If this code breaks, please contact both Yoshioka and me.
+--*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+/*--
+   return version like "0.9.5d, 4-Sept-1999".
+--*/
+const char * BZ_API(BZ2_bzlibVersion)(void)
+{
+   return BZ_VERSION;
+}
+
+
+#ifndef BZ_NO_STDIO
+/*---------------------------------------------------*/
+
+#if defined(_WIN32) || defined(OS2) || defined(MSDOS)
+#   include 
+#   include 
+#   define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
+#else
+#   define SET_BINARY_MODE(file)
+#endif
+static
+BZFILE * bzopen_or_bzdopen
+               ( const char *path,   /* no use when bzdopen */
+                 int fd,             /* no use when bzdopen */
+                 const char *mode,
+                 int open_mode)      /* bzopen: 0, bzdopen:1 */
+{
+   int    bzerr;
+   char   unused[BZ_MAX_UNUSED];
+   int    blockSize100k = 9;
+   int    writing       = 0;
+   char   mode2[10]     = "";
+   FILE   *fp           = NULL;
+   BZFILE *bzfp         = NULL;
+   int    verbosity     = 0;
+   int    workFactor    = 30;
+   int    smallMode     = 0;
+   int    nUnused       = 0; 
+
+   if (mode == NULL) return NULL;
+   while (*mode) {
+      switch (*mode) {
+      case 'r':
+         writing = 0; break;
+      case 'w':
+         writing = 1; break;
+      case 's':
+         smallMode = 1; break;
+      default:
+         if (isdigit((int)(*mode))) {
+            blockSize100k = *mode-BZ_HDR_0;
+         }
+      }
+      mode++;
+   }
+   strcat(mode2, writing ? "w" : "r" );
+   strcat(mode2,"b");   /* binary mode */
+
+   if (open_mode==0) {
+      if (path==NULL || strcmp(path,"")==0) {
+        fp = (writing ? stdout : stdin);
+        SET_BINARY_MODE(fp);
+      } else {
+        fp = fopen(path,mode2);
+      }
+   } else {
+#ifdef BZ_STRICT_ANSI
+      fp = NULL;
+#else
+      fp = fdopen(fd,mode2);
+#endif
+   }
+   if (fp == NULL) return NULL;
+
+   if (writing) {
+      /* Guard against total chaos and anarchy -- JRS */
+      if (blockSize100k < 1) blockSize100k = 1;
+      if (blockSize100k > 9) blockSize100k = 9; 
+      bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k,
+                             verbosity,workFactor);
+   } else {
+      bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode,
+                            unused,nUnused);
+   }
+   if (bzfp == NULL) {
+      if (fp != stdin && fp != stdout) fclose(fp);
+      return NULL;
+   }
+   return bzfp;
+}
+
+
+/*---------------------------------------------------*/
+/*--
+   open file for read or write.
+      ex) bzopen("file","w9")
+      case path="" or NULL => use stdin or stdout.
+--*/
+BZFILE * BZ_API(BZ2_bzopen)
+               ( const char *path,
+                 const char *mode )
+{
+   return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0);
+}
+
+
+/*---------------------------------------------------*/
+BZFILE * BZ_API(BZ2_bzdopen)
+               ( int fd,
+                 const char *mode )
+{
+   return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1);
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len )
+{
+   int bzerr, nread;
+   if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0;
+   nread = BZ2_bzRead(&bzerr,b,buf,len);
+   if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) {
+      return nread;
+   } else {
+      return -1;
+   }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len )
+{
+   int bzerr;
+
+   BZ2_bzWrite(&bzerr,b,buf,len);
+   if(bzerr == BZ_OK){
+      return len;
+   }else{
+      return -1;
+   }
+}
+
+
+/*---------------------------------------------------*/
+int BZ_API(BZ2_bzflush) (BZFILE *b)
+{
+   /* do nothing now... */
+   return 0;
+}
+
+
+/*---------------------------------------------------*/
+void BZ_API(BZ2_bzclose) (BZFILE* b)
+{
+   int bzerr;
+   FILE *fp;
+   
+   if (b==NULL) {return;}
+   fp = ((bzFile *)b)->handle;
+   if(((bzFile*)b)->writing){
+      BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL);
+      if(bzerr != BZ_OK){
+         BZ2_bzWriteClose(NULL,b,1,NULL,NULL);
+      }
+   }else{
+      BZ2_bzReadClose(&bzerr,b);
+   }
+   if(fp!=stdin && fp!=stdout){
+      fclose(fp);
+   }
+}
+
+
+/*---------------------------------------------------*/
+/*--
+   return last error code 
+--*/
+static const char *bzerrorstrings[] = {
+       "OK"
+      ,"SEQUENCE_ERROR"
+      ,"PARAM_ERROR"
+      ,"MEM_ERROR"
+      ,"DATA_ERROR"
+      ,"DATA_ERROR_MAGIC"
+      ,"IO_ERROR"
+      ,"UNEXPECTED_EOF"
+      ,"OUTBUFF_FULL"
+      ,"CONFIG_ERROR"
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+      ,"???"   /* for future */
+};
+
+
+const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum)
+{
+   int err = ((bzFile *)b)->lastErr;
+
+   if(err>0) err = 0;
+   *errnum = err;
+   return bzerrorstrings[err*-1];
+}
+#endif
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                           bzlib.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/project/jni/bzip2/bzlib_private.h b/project/jni/bzip2/bzlib_private.h
new file mode 100644
index 000000000..5d0217f46
--- /dev/null
+++ b/project/jni/bzip2/bzlib_private.h
@@ -0,0 +1,509 @@
+
+/*-------------------------------------------------------------*/
+/*--- Private header file for the library.                  ---*/
+/*---                                       bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#ifndef _BZLIB_PRIVATE_H
+#define _BZLIB_PRIVATE_H
+
+#include 
+
+#ifndef BZ_NO_STDIO
+#include 
+#include 
+#include 
+#endif
+
+#include "bzlib.h"
+
+
+
+/*-- General stuff. --*/
+
+#define BZ_VERSION  "1.0.6, 6-Sept-2010"
+
+typedef char            Char;
+typedef unsigned char   Bool;
+typedef unsigned char   UChar;
+typedef int             Int32;
+typedef unsigned int    UInt32;
+typedef short           Int16;
+typedef unsigned short  UInt16;
+
+#define True  ((Bool)1)
+#define False ((Bool)0)
+
+#ifndef __GNUC__
+#define __inline__  /* */
+#endif 
+
+#ifndef BZ_NO_STDIO
+
+extern void BZ2_bz__AssertH__fail ( int errcode );
+#define AssertH(cond,errcode) \
+   { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); }
+
+#if BZ_DEBUG
+#define AssertD(cond,msg) \
+   { if (!(cond)) {       \
+      fprintf ( stderr,   \
+        "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\
+      exit(1); \
+   }}
+#else
+#define AssertD(cond,msg) /* */
+#endif
+
+#define VPrintf0(zf) \
+   fprintf(stderr,zf)
+#define VPrintf1(zf,za1) \
+   fprintf(stderr,zf,za1)
+#define VPrintf2(zf,za1,za2) \
+   fprintf(stderr,zf,za1,za2)
+#define VPrintf3(zf,za1,za2,za3) \
+   fprintf(stderr,zf,za1,za2,za3)
+#define VPrintf4(zf,za1,za2,za3,za4) \
+   fprintf(stderr,zf,za1,za2,za3,za4)
+#define VPrintf5(zf,za1,za2,za3,za4,za5) \
+   fprintf(stderr,zf,za1,za2,za3,za4,za5)
+
+#else
+
+extern void bz_internal_error ( int errcode );
+#define AssertH(cond,errcode) \
+   { if (!(cond)) bz_internal_error ( errcode ); }
+#define AssertD(cond,msg)                do { } while (0)
+#define VPrintf0(zf)                     do { } while (0)
+#define VPrintf1(zf,za1)                 do { } while (0)
+#define VPrintf2(zf,za1,za2)             do { } while (0)
+#define VPrintf3(zf,za1,za2,za3)         do { } while (0)
+#define VPrintf4(zf,za1,za2,za3,za4)     do { } while (0)
+#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0)
+
+#endif
+
+
+#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1)
+#define BZFREE(ppp)  (strm->bzfree)(strm->opaque,(ppp))
+
+
+/*-- Header bytes. --*/
+
+#define BZ_HDR_B 0x42   /* 'B' */
+#define BZ_HDR_Z 0x5a   /* 'Z' */
+#define BZ_HDR_h 0x68   /* 'h' */
+#define BZ_HDR_0 0x30   /* '0' */
+  
+/*-- Constants for the back end. --*/
+
+#define BZ_MAX_ALPHA_SIZE 258
+#define BZ_MAX_CODE_LEN    23
+
+#define BZ_RUNA 0
+#define BZ_RUNB 1
+
+#define BZ_N_GROUPS 6
+#define BZ_G_SIZE   50
+#define BZ_N_ITERS  4
+
+#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
+
+
+
+/*-- Stuff for randomising repetitive blocks. --*/
+
+extern Int32 BZ2_rNums[512];
+
+#define BZ_RAND_DECLS                          \
+   Int32 rNToGo;                               \
+   Int32 rTPos                                 \
+
+#define BZ_RAND_INIT_MASK                      \
+   s->rNToGo = 0;                              \
+   s->rTPos  = 0                               \
+
+#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0)
+
+#define BZ_RAND_UPD_MASK                       \
+   if (s->rNToGo == 0) {                       \
+      s->rNToGo = BZ2_rNums[s->rTPos];         \
+      s->rTPos++;                              \
+      if (s->rTPos == 512) s->rTPos = 0;       \
+   }                                           \
+   s->rNToGo--;
+
+
+
+/*-- Stuff for doing CRCs. --*/
+
+extern UInt32 BZ2_crc32Table[256];
+
+#define BZ_INITIALISE_CRC(crcVar)              \
+{                                              \
+   crcVar = 0xffffffffL;                       \
+}
+
+#define BZ_FINALISE_CRC(crcVar)                \
+{                                              \
+   crcVar = ~(crcVar);                         \
+}
+
+#define BZ_UPDATE_CRC(crcVar,cha)              \
+{                                              \
+   crcVar = (crcVar << 8) ^                    \
+            BZ2_crc32Table[(crcVar >> 24) ^    \
+                           ((UChar)cha)];      \
+}
+
+
+
+/*-- States and modes for compression. --*/
+
+#define BZ_M_IDLE      1
+#define BZ_M_RUNNING   2
+#define BZ_M_FLUSHING  3
+#define BZ_M_FINISHING 4
+
+#define BZ_S_OUTPUT    1
+#define BZ_S_INPUT     2
+
+#define BZ_N_RADIX 2
+#define BZ_N_QSORT 12
+#define BZ_N_SHELL 18
+#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2)
+
+
+
+
+/*-- Structure holding all the compression-side stuff. --*/
+
+typedef
+   struct {
+      /* pointer back to the struct bz_stream */
+      bz_stream* strm;
+
+      /* mode this stream is in, and whether inputting */
+      /* or outputting data */
+      Int32    mode;
+      Int32    state;
+
+      /* remembers avail_in when flush/finish requested */
+      UInt32   avail_in_expect;
+
+      /* for doing the block sorting */
+      UInt32*  arr1;
+      UInt32*  arr2;
+      UInt32*  ftab;
+      Int32    origPtr;
+
+      /* aliases for arr1 and arr2 */
+      UInt32*  ptr;
+      UChar*   block;
+      UInt16*  mtfv;
+      UChar*   zbits;
+
+      /* for deciding when to use the fallback sorting algorithm */
+      Int32    workFactor;
+
+      /* run-length-encoding of the input */
+      UInt32   state_in_ch;
+      Int32    state_in_len;
+      BZ_RAND_DECLS;
+
+      /* input and output limits and current posns */
+      Int32    nblock;
+      Int32    nblockMAX;
+      Int32    numZ;
+      Int32    state_out_pos;
+
+      /* map of bytes used in block */
+      Int32    nInUse;
+      Bool     inUse[256];
+      UChar    unseqToSeq[256];
+
+      /* the buffer for bit stream creation */
+      UInt32   bsBuff;
+      Int32    bsLive;
+
+      /* block and combined CRCs */
+      UInt32   blockCRC;
+      UInt32   combinedCRC;
+
+      /* misc administratium */
+      Int32    verbosity;
+      Int32    blockNo;
+      Int32    blockSize100k;
+
+      /* stuff for coding the MTF values */
+      Int32    nMTF;
+      Int32    mtfFreq    [BZ_MAX_ALPHA_SIZE];
+      UChar    selector   [BZ_MAX_SELECTORS];
+      UChar    selectorMtf[BZ_MAX_SELECTORS];
+
+      UChar    len     [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    code    [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    rfreq   [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      /* second dimension: only 3 needed; 4 makes index calculations faster */
+      UInt32   len_pack[BZ_MAX_ALPHA_SIZE][4];
+
+   }
+   EState;
+
+
+
+/*-- externs for compression. --*/
+
+extern void 
+BZ2_blockSort ( EState* );
+
+extern void 
+BZ2_compressBlock ( EState*, Bool );
+
+extern void 
+BZ2_bsInitWrite ( EState* );
+
+extern void 
+BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 );
+
+extern void 
+BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 );
+
+
+
+/*-- states for decompression. --*/
+
+#define BZ_X_IDLE        1
+#define BZ_X_OUTPUT      2
+
+#define BZ_X_MAGIC_1     10
+#define BZ_X_MAGIC_2     11
+#define BZ_X_MAGIC_3     12
+#define BZ_X_MAGIC_4     13
+#define BZ_X_BLKHDR_1    14
+#define BZ_X_BLKHDR_2    15
+#define BZ_X_BLKHDR_3    16
+#define BZ_X_BLKHDR_4    17
+#define BZ_X_BLKHDR_5    18
+#define BZ_X_BLKHDR_6    19
+#define BZ_X_BCRC_1      20
+#define BZ_X_BCRC_2      21
+#define BZ_X_BCRC_3      22
+#define BZ_X_BCRC_4      23
+#define BZ_X_RANDBIT     24
+#define BZ_X_ORIGPTR_1   25
+#define BZ_X_ORIGPTR_2   26
+#define BZ_X_ORIGPTR_3   27
+#define BZ_X_MAPPING_1   28
+#define BZ_X_MAPPING_2   29
+#define BZ_X_SELECTOR_1  30
+#define BZ_X_SELECTOR_2  31
+#define BZ_X_SELECTOR_3  32
+#define BZ_X_CODING_1    33
+#define BZ_X_CODING_2    34
+#define BZ_X_CODING_3    35
+#define BZ_X_MTF_1       36
+#define BZ_X_MTF_2       37
+#define BZ_X_MTF_3       38
+#define BZ_X_MTF_4       39
+#define BZ_X_MTF_5       40
+#define BZ_X_MTF_6       41
+#define BZ_X_ENDHDR_2    42
+#define BZ_X_ENDHDR_3    43
+#define BZ_X_ENDHDR_4    44
+#define BZ_X_ENDHDR_5    45
+#define BZ_X_ENDHDR_6    46
+#define BZ_X_CCRC_1      47
+#define BZ_X_CCRC_2      48
+#define BZ_X_CCRC_3      49
+#define BZ_X_CCRC_4      50
+
+
+
+/*-- Constants for the fast MTF decoder. --*/
+
+#define MTFA_SIZE 4096
+#define MTFL_SIZE 16
+
+
+
+/*-- Structure holding all the decompression-side stuff. --*/
+
+typedef
+   struct {
+      /* pointer back to the struct bz_stream */
+      bz_stream* strm;
+
+      /* state indicator for this stream */
+      Int32    state;
+
+      /* for doing the final run-length decoding */
+      UChar    state_out_ch;
+      Int32    state_out_len;
+      Bool     blockRandomised;
+      BZ_RAND_DECLS;
+
+      /* the buffer for bit stream reading */
+      UInt32   bsBuff;
+      Int32    bsLive;
+
+      /* misc administratium */
+      Int32    blockSize100k;
+      Bool     smallDecompress;
+      Int32    currBlockNo;
+      Int32    verbosity;
+
+      /* for undoing the Burrows-Wheeler transform */
+      Int32    origPtr;
+      UInt32   tPos;
+      Int32    k0;
+      Int32    unzftab[256];
+      Int32    nblock_used;
+      Int32    cftab[257];
+      Int32    cftabCopy[257];
+
+      /* for undoing the Burrows-Wheeler transform (FAST) */
+      UInt32   *tt;
+
+      /* for undoing the Burrows-Wheeler transform (SMALL) */
+      UInt16   *ll16;
+      UChar    *ll4;
+
+      /* stored and calculated CRCs */
+      UInt32   storedBlockCRC;
+      UInt32   storedCombinedCRC;
+      UInt32   calculatedBlockCRC;
+      UInt32   calculatedCombinedCRC;
+
+      /* map of bytes used in block */
+      Int32    nInUse;
+      Bool     inUse[256];
+      Bool     inUse16[16];
+      UChar    seqToUnseq[256];
+
+      /* for decoding the MTF values */
+      UChar    mtfa   [MTFA_SIZE];
+      Int32    mtfbase[256 / MTFL_SIZE];
+      UChar    selector   [BZ_MAX_SELECTORS];
+      UChar    selectorMtf[BZ_MAX_SELECTORS];
+      UChar    len  [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+
+      Int32    limit  [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    base   [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    perm   [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+      Int32    minLens[BZ_N_GROUPS];
+
+      /* save area for scalars in the main decompress code */
+      Int32    save_i;
+      Int32    save_j;
+      Int32    save_t;
+      Int32    save_alphaSize;
+      Int32    save_nGroups;
+      Int32    save_nSelectors;
+      Int32    save_EOB;
+      Int32    save_groupNo;
+      Int32    save_groupPos;
+      Int32    save_nextSym;
+      Int32    save_nblockMAX;
+      Int32    save_nblock;
+      Int32    save_es;
+      Int32    save_N;
+      Int32    save_curr;
+      Int32    save_zt;
+      Int32    save_zn; 
+      Int32    save_zvec;
+      Int32    save_zj;
+      Int32    save_gSel;
+      Int32    save_gMinlen;
+      Int32*   save_gLimit;
+      Int32*   save_gBase;
+      Int32*   save_gPerm;
+
+   }
+   DState;
+
+
+
+/*-- Macros for decompression. --*/
+
+#define BZ_GET_FAST(cccc)                     \
+    /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+    if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
+    s->tPos = s->tt[s->tPos];                 \
+    cccc = (UChar)(s->tPos & 0xff);           \
+    s->tPos >>= 8;
+
+#define BZ_GET_FAST_C(cccc)                   \
+    /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+    if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \
+    c_tPos = c_tt[c_tPos];                    \
+    cccc = (UChar)(c_tPos & 0xff);            \
+    c_tPos >>= 8;
+
+#define SET_LL4(i,n)                                          \
+   { if (((i) & 0x1) == 0)                                    \
+        s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else    \
+        s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4);  \
+   }
+
+#define GET_LL4(i)                             \
+   ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF)
+
+#define SET_LL(i,n)                          \
+   { s->ll16[i] = (UInt16)(n & 0x0000ffff);  \
+     SET_LL4(i, n >> 16);                    \
+   }
+
+#define GET_LL(i) \
+   (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16))
+
+#define BZ_GET_SMALL(cccc)                            \
+    /* c_tPos is unsigned, hence test < 0 is pointless. */ \
+    if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \
+    cccc = BZ2_indexIntoF ( s->tPos, s->cftab );    \
+    s->tPos = GET_LL(s->tPos);
+
+
+/*-- externs for decompression. --*/
+
+extern Int32 
+BZ2_indexIntoF ( Int32, Int32* );
+
+extern Int32 
+BZ2_decompress ( DState* );
+
+extern void 
+BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*,
+                           Int32,  Int32, Int32 );
+
+
+#endif
+
+
+/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/
+
+#ifdef BZ_NO_STDIO
+#ifndef NULL
+#define NULL 0
+#endif
+#endif
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                   bzlib_private.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/project/jni/bzip2/compress.c b/project/jni/bzip2/compress.c
new file mode 100644
index 000000000..caf769601
--- /dev/null
+++ b/project/jni/bzip2/compress.c
@@ -0,0 +1,672 @@
+
+/*-------------------------------------------------------------*/
+/*--- Compression machinery (not incl block sorting)        ---*/
+/*---                                            compress.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+/* CHANGES
+    0.9.0    -- original version.
+    0.9.0a/b -- no changes in this file.
+    0.9.0c   -- changed setting of nGroups in sendMTFValues() 
+                so as to do a bit better on small files
+*/
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+/*--- Bit stream I/O                              ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+void BZ2_bsInitWrite ( EState* s )
+{
+   s->bsLive = 0;
+   s->bsBuff = 0;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsFinishWrite ( EState* s )
+{
+   while (s->bsLive > 0) {
+      s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24);
+      s->numZ++;
+      s->bsBuff <<= 8;
+      s->bsLive -= 8;
+   }
+}
+
+
+/*---------------------------------------------------*/
+#define bsNEEDW(nz)                           \
+{                                             \
+   while (s->bsLive >= 8) {                   \
+      s->zbits[s->numZ]                       \
+         = (UChar)(s->bsBuff >> 24);          \
+      s->numZ++;                              \
+      s->bsBuff <<= 8;                        \
+      s->bsLive -= 8;                         \
+   }                                          \
+}
+
+
+/*---------------------------------------------------*/
+static
+__inline__
+void bsW ( EState* s, Int32 n, UInt32 v )
+{
+   bsNEEDW ( n );
+   s->bsBuff |= (v << (32 - s->bsLive - n));
+   s->bsLive += n;
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutUInt32 ( EState* s, UInt32 u )
+{
+   bsW ( s, 8, (u >> 24) & 0xffL );
+   bsW ( s, 8, (u >> 16) & 0xffL );
+   bsW ( s, 8, (u >>  8) & 0xffL );
+   bsW ( s, 8,  u        & 0xffL );
+}
+
+
+/*---------------------------------------------------*/
+static
+void bsPutUChar ( EState* s, UChar c )
+{
+   bsW( s, 8, (UInt32)c );
+}
+
+
+/*---------------------------------------------------*/
+/*--- The back end proper                         ---*/
+/*---------------------------------------------------*/
+
+/*---------------------------------------------------*/
+static
+void makeMaps_e ( EState* s )
+{
+   Int32 i;
+   s->nInUse = 0;
+   for (i = 0; i < 256; i++)
+      if (s->inUse[i]) {
+         s->unseqToSeq[i] = s->nInUse;
+         s->nInUse++;
+      }
+}
+
+
+/*---------------------------------------------------*/
+static
+void generateMTFValues ( EState* s )
+{
+   UChar   yy[256];
+   Int32   i, j;
+   Int32   zPend;
+   Int32   wr;
+   Int32   EOB;
+
+   /* 
+      After sorting (eg, here),
+         s->arr1 [ 0 .. s->nblock-1 ] holds sorted order,
+         and
+         ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] 
+         holds the original block data.
+
+      The first thing to do is generate the MTF values,
+      and put them in
+         ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ].
+      Because there are strictly fewer or equal MTF values
+      than block values, ptr values in this area are overwritten
+      with MTF values only when they are no longer needed.
+
+      The final compressed bitstream is generated into the
+      area starting at
+         (UChar*) (&((UChar*)s->arr2)[s->nblock])
+
+      These storage aliases are set up in bzCompressInit(),
+      except for the last one, which is arranged in 
+      compressBlock().
+   */
+   UInt32* ptr   = s->ptr;
+   UChar* block  = s->block;
+   UInt16* mtfv  = s->mtfv;
+
+   makeMaps_e ( s );
+   EOB = s->nInUse+1;
+
+   for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0;
+
+   wr = 0;
+   zPend = 0;
+   for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i;
+
+   for (i = 0; i < s->nblock; i++) {
+      UChar ll_i;
+      AssertD ( wr <= i, "generateMTFValues(1)" );
+      j = ptr[i]-1; if (j < 0) j += s->nblock;
+      ll_i = s->unseqToSeq[block[j]];
+      AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" );
+
+      if (yy[0] == ll_i) { 
+         zPend++;
+      } else {
+
+         if (zPend > 0) {
+            zPend--;
+            while (True) {
+               if (zPend & 1) {
+                  mtfv[wr] = BZ_RUNB; wr++; 
+                  s->mtfFreq[BZ_RUNB]++; 
+               } else {
+                  mtfv[wr] = BZ_RUNA; wr++; 
+                  s->mtfFreq[BZ_RUNA]++; 
+               }
+               if (zPend < 2) break;
+               zPend = (zPend - 2) / 2;
+            };
+            zPend = 0;
+         }
+         {
+            register UChar  rtmp;
+            register UChar* ryy_j;
+            register UChar  rll_i;
+            rtmp  = yy[1];
+            yy[1] = yy[0];
+            ryy_j = &(yy[1]);
+            rll_i = ll_i;
+            while ( rll_i != rtmp ) {
+               register UChar rtmp2;
+               ryy_j++;
+               rtmp2  = rtmp;
+               rtmp   = *ryy_j;
+               *ryy_j = rtmp2;
+            };
+            yy[0] = rtmp;
+            j = ryy_j - &(yy[0]);
+            mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++;
+         }
+
+      }
+   }
+
+   if (zPend > 0) {
+      zPend--;
+      while (True) {
+         if (zPend & 1) {
+            mtfv[wr] = BZ_RUNB; wr++; 
+            s->mtfFreq[BZ_RUNB]++; 
+         } else {
+            mtfv[wr] = BZ_RUNA; wr++; 
+            s->mtfFreq[BZ_RUNA]++; 
+         }
+         if (zPend < 2) break;
+         zPend = (zPend - 2) / 2;
+      };
+      zPend = 0;
+   }
+
+   mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++;
+
+   s->nMTF = wr;
+}
+
+
+/*---------------------------------------------------*/
+#define BZ_LESSER_ICOST  0
+#define BZ_GREATER_ICOST 15
+
+static
+void sendMTFValues ( EState* s )
+{
+   Int32 v, t, i, j, gs, ge, totc, bt, bc, iter;
+   Int32 nSelectors, alphaSize, minLen, maxLen, selCtr;
+   Int32 nGroups, nBytes;
+
+   /*--
+   UChar  len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+   is a global since the decoder also needs it.
+
+   Int32  code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+   Int32  rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
+   are also globals only used in this proc.
+   Made global to keep stack frame size small.
+   --*/
+
+
+   UInt16 cost[BZ_N_GROUPS];
+   Int32  fave[BZ_N_GROUPS];
+
+   UInt16* mtfv = s->mtfv;
+
+   if (s->verbosity >= 3)
+      VPrintf3( "      %d in block, %d after MTF & 1-2 coding, "
+                "%d+2 syms in use\n", 
+                s->nblock, s->nMTF, s->nInUse );
+
+   alphaSize = s->nInUse+2;
+   for (t = 0; t < BZ_N_GROUPS; t++)
+      for (v = 0; v < alphaSize; v++)
+         s->len[t][v] = BZ_GREATER_ICOST;
+
+   /*--- Decide how many coding tables to use ---*/
+   AssertH ( s->nMTF > 0, 3001 );
+   if (s->nMTF < 200)  nGroups = 2; else
+   if (s->nMTF < 600)  nGroups = 3; else
+   if (s->nMTF < 1200) nGroups = 4; else
+   if (s->nMTF < 2400) nGroups = 5; else
+                       nGroups = 6;
+
+   /*--- Generate an initial set of coding tables ---*/
+   { 
+      Int32 nPart, remF, tFreq, aFreq;
+
+      nPart = nGroups;
+      remF  = s->nMTF;
+      gs = 0;
+      while (nPart > 0) {
+         tFreq = remF / nPart;
+         ge = gs-1;
+         aFreq = 0;
+         while (aFreq < tFreq && ge < alphaSize-1) {
+            ge++;
+            aFreq += s->mtfFreq[ge];
+         }
+
+         if (ge > gs 
+             && nPart != nGroups && nPart != 1 
+             && ((nGroups-nPart) % 2 == 1)) {
+            aFreq -= s->mtfFreq[ge];
+            ge--;
+         }
+
+         if (s->verbosity >= 3)
+            VPrintf5( "      initial group %d, [%d .. %d], "
+                      "has %d syms (%4.1f%%)\n",
+                      nPart, gs, ge, aFreq, 
+                      (100.0 * (float)aFreq) / (float)(s->nMTF) );
+ 
+         for (v = 0; v < alphaSize; v++)
+            if (v >= gs && v <= ge) 
+               s->len[nPart-1][v] = BZ_LESSER_ICOST; else
+               s->len[nPart-1][v] = BZ_GREATER_ICOST;
+ 
+         nPart--;
+         gs = ge+1;
+         remF -= aFreq;
+      }
+   }
+
+   /*--- 
+      Iterate up to BZ_N_ITERS times to improve the tables.
+   ---*/
+   for (iter = 0; iter < BZ_N_ITERS; iter++) {
+
+      for (t = 0; t < nGroups; t++) fave[t] = 0;
+
+      for (t = 0; t < nGroups; t++)
+         for (v = 0; v < alphaSize; v++)
+            s->rfreq[t][v] = 0;
+
+      /*---
+        Set up an auxiliary length table which is used to fast-track
+	the common case (nGroups == 6). 
+      ---*/
+      if (nGroups == 6) {
+         for (v = 0; v < alphaSize; v++) {
+            s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v];
+            s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v];
+            s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v];
+	 }
+      }
+
+      nSelectors = 0;
+      totc = 0;
+      gs = 0;
+      while (True) {
+
+         /*--- Set group start & end marks. --*/
+         if (gs >= s->nMTF) break;
+         ge = gs + BZ_G_SIZE - 1; 
+         if (ge >= s->nMTF) ge = s->nMTF-1;
+
+         /*-- 
+            Calculate the cost of this group as coded
+            by each of the coding tables.
+         --*/
+         for (t = 0; t < nGroups; t++) cost[t] = 0;
+
+         if (nGroups == 6 && 50 == ge-gs+1) {
+            /*--- fast track the common case ---*/
+            register UInt32 cost01, cost23, cost45;
+            register UInt16 icv;
+            cost01 = cost23 = cost45 = 0;
+
+#           define BZ_ITER(nn)                \
+               icv = mtfv[gs+(nn)];           \
+               cost01 += s->len_pack[icv][0]; \
+               cost23 += s->len_pack[icv][1]; \
+               cost45 += s->len_pack[icv][2]; \
+
+            BZ_ITER(0);  BZ_ITER(1);  BZ_ITER(2);  BZ_ITER(3);  BZ_ITER(4);
+            BZ_ITER(5);  BZ_ITER(6);  BZ_ITER(7);  BZ_ITER(8);  BZ_ITER(9);
+            BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14);
+            BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19);
+            BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24);
+            BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29);
+            BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34);
+            BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39);
+            BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44);
+            BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49);
+
+#           undef BZ_ITER
+
+            cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16;
+            cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16;
+            cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16;
+
+         } else {
+	    /*--- slow version which correctly handles all situations ---*/
+            for (i = gs; i <= ge; i++) { 
+               UInt16 icv = mtfv[i];
+               for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv];
+            }
+         }
+ 
+         /*-- 
+            Find the coding table which is best for this group,
+            and record its identity in the selector table.
+         --*/
+         bc = 999999999; bt = -1;
+         for (t = 0; t < nGroups; t++)
+            if (cost[t] < bc) { bc = cost[t]; bt = t; };
+         totc += bc;
+         fave[bt]++;
+         s->selector[nSelectors] = bt;
+         nSelectors++;
+
+         /*-- 
+            Increment the symbol frequencies for the selected table.
+          --*/
+         if (nGroups == 6 && 50 == ge-gs+1) {
+            /*--- fast track the common case ---*/
+
+#           define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++
+
+            BZ_ITUR(0);  BZ_ITUR(1);  BZ_ITUR(2);  BZ_ITUR(3);  BZ_ITUR(4);
+            BZ_ITUR(5);  BZ_ITUR(6);  BZ_ITUR(7);  BZ_ITUR(8);  BZ_ITUR(9);
+            BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14);
+            BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19);
+            BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24);
+            BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29);
+            BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34);
+            BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39);
+            BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44);
+            BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49);
+
+#           undef BZ_ITUR
+
+         } else {
+	    /*--- slow version which correctly handles all situations ---*/
+            for (i = gs; i <= ge; i++)
+               s->rfreq[bt][ mtfv[i] ]++;
+         }
+
+         gs = ge+1;
+      }
+      if (s->verbosity >= 3) {
+         VPrintf2 ( "      pass %d: size is %d, grp uses are ", 
+                   iter+1, totc/8 );
+         for (t = 0; t < nGroups; t++)
+            VPrintf1 ( "%d ", fave[t] );
+         VPrintf0 ( "\n" );
+      }
+
+      /*--
+        Recompute the tables based on the accumulated frequencies.
+      --*/
+      /* maxLen was changed from 20 to 17 in bzip2-1.0.3.  See 
+         comment in huffman.c for details. */
+      for (t = 0; t < nGroups; t++)
+         BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), 
+                                 alphaSize, 17 /*20*/ );
+   }
+
+
+   AssertH( nGroups < 8, 3002 );
+   AssertH( nSelectors < 32768 &&
+            nSelectors <= (2 + (900000 / BZ_G_SIZE)),
+            3003 );
+
+
+   /*--- Compute MTF values for the selectors. ---*/
+   {
+      UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp;
+      for (i = 0; i < nGroups; i++) pos[i] = i;
+      for (i = 0; i < nSelectors; i++) {
+         ll_i = s->selector[i];
+         j = 0;
+         tmp = pos[j];
+         while ( ll_i != tmp ) {
+            j++;
+            tmp2 = tmp;
+            tmp = pos[j];
+            pos[j] = tmp2;
+         };
+         pos[0] = tmp;
+         s->selectorMtf[i] = j;
+      }
+   };
+
+   /*--- Assign actual codes for the tables. --*/
+   for (t = 0; t < nGroups; t++) {
+      minLen = 32;
+      maxLen = 0;
+      for (i = 0; i < alphaSize; i++) {
+         if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+         if (s->len[t][i] < minLen) minLen = s->len[t][i];
+      }
+      AssertH ( !(maxLen > 17 /*20*/ ), 3004 );
+      AssertH ( !(minLen < 1),  3005 );
+      BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), 
+                          minLen, maxLen, alphaSize );
+   }
+
+   /*--- Transmit the mapping table. ---*/
+   { 
+      Bool inUse16[16];
+      for (i = 0; i < 16; i++) {
+          inUse16[i] = False;
+          for (j = 0; j < 16; j++)
+             if (s->inUse[i * 16 + j]) inUse16[i] = True;
+      }
+     
+      nBytes = s->numZ;
+      for (i = 0; i < 16; i++)
+         if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0);
+
+      for (i = 0; i < 16; i++)
+         if (inUse16[i])
+            for (j = 0; j < 16; j++) {
+               if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0);
+            }
+
+      if (s->verbosity >= 3) 
+         VPrintf1( "      bytes: mapping %d, ", s->numZ-nBytes );
+   }
+
+   /*--- Now the selectors. ---*/
+   nBytes = s->numZ;
+   bsW ( s, 3, nGroups );
+   bsW ( s, 15, nSelectors );
+   for (i = 0; i < nSelectors; i++) { 
+      for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1);
+      bsW(s,1,0);
+   }
+   if (s->verbosity >= 3)
+      VPrintf1( "selectors %d, ", s->numZ-nBytes );
+
+   /*--- Now the coding tables. ---*/
+   nBytes = s->numZ;
+
+   for (t = 0; t < nGroups; t++) {
+      Int32 curr = s->len[t][0];
+      bsW ( s, 5, curr );
+      for (i = 0; i < alphaSize; i++) {
+         while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ };
+         while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ };
+         bsW ( s, 1, 0 );
+      }
+   }
+
+   if (s->verbosity >= 3)
+      VPrintf1 ( "code lengths %d, ", s->numZ-nBytes );
+
+   /*--- And finally, the block data proper ---*/
+   nBytes = s->numZ;
+   selCtr = 0;
+   gs = 0;
+   while (True) {
+      if (gs >= s->nMTF) break;
+      ge = gs + BZ_G_SIZE - 1; 
+      if (ge >= s->nMTF) ge = s->nMTF-1;
+      AssertH ( s->selector[selCtr] < nGroups, 3006 );
+
+      if (nGroups == 6 && 50 == ge-gs+1) {
+            /*--- fast track the common case ---*/
+            UInt16 mtfv_i;
+            UChar* s_len_sel_selCtr 
+               = &(s->len[s->selector[selCtr]][0]);
+            Int32* s_code_sel_selCtr
+               = &(s->code[s->selector[selCtr]][0]);
+
+#           define BZ_ITAH(nn)                      \
+               mtfv_i = mtfv[gs+(nn)];              \
+               bsW ( s,                             \
+                     s_len_sel_selCtr[mtfv_i],      \
+                     s_code_sel_selCtr[mtfv_i] )
+
+            BZ_ITAH(0);  BZ_ITAH(1);  BZ_ITAH(2);  BZ_ITAH(3);  BZ_ITAH(4);
+            BZ_ITAH(5);  BZ_ITAH(6);  BZ_ITAH(7);  BZ_ITAH(8);  BZ_ITAH(9);
+            BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14);
+            BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19);
+            BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24);
+            BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29);
+            BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34);
+            BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39);
+            BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44);
+            BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49);
+
+#           undef BZ_ITAH
+
+      } else {
+	 /*--- slow version which correctly handles all situations ---*/
+         for (i = gs; i <= ge; i++) {
+            bsW ( s, 
+                  s->len  [s->selector[selCtr]] [mtfv[i]],
+                  s->code [s->selector[selCtr]] [mtfv[i]] );
+         }
+      }
+
+
+      gs = ge+1;
+      selCtr++;
+   }
+   AssertH( selCtr == nSelectors, 3007 );
+
+   if (s->verbosity >= 3)
+      VPrintf1( "codes %d\n", s->numZ-nBytes );
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_compressBlock ( EState* s, Bool is_last_block )
+{
+   if (s->nblock > 0) {
+
+      BZ_FINALISE_CRC ( s->blockCRC );
+      s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31);
+      s->combinedCRC ^= s->blockCRC;
+      if (s->blockNo > 1) s->numZ = 0;
+
+      if (s->verbosity >= 2)
+         VPrintf4( "    block %d: crc = 0x%08x, "
+                   "combined CRC = 0x%08x, size = %d\n",
+                   s->blockNo, s->blockCRC, s->combinedCRC, s->nblock );
+
+      BZ2_blockSort ( s );
+   }
+
+   s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]);
+
+   /*-- If this is the first block, create the stream header. --*/
+   if (s->blockNo == 1) {
+      BZ2_bsInitWrite ( s );
+      bsPutUChar ( s, BZ_HDR_B );
+      bsPutUChar ( s, BZ_HDR_Z );
+      bsPutUChar ( s, BZ_HDR_h );
+      bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) );
+   }
+
+   if (s->nblock > 0) {
+
+      bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 );
+      bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 );
+      bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 );
+
+      /*-- Now the block's CRC, so it is in a known place. --*/
+      bsPutUInt32 ( s, s->blockCRC );
+
+      /*-- 
+         Now a single bit indicating (non-)randomisation. 
+         As of version 0.9.5, we use a better sorting algorithm
+         which makes randomisation unnecessary.  So always set
+         the randomised bit to 'no'.  Of course, the decoder
+         still needs to be able to handle randomised blocks
+         so as to maintain backwards compatibility with
+         older versions of bzip2.
+      --*/
+      bsW(s,1,0);
+
+      bsW ( s, 24, s->origPtr );
+      generateMTFValues ( s );
+      sendMTFValues ( s );
+   }
+
+
+   /*-- If this is the last block, add the stream trailer. --*/
+   if (is_last_block) {
+
+      bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 );
+      bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 );
+      bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 );
+      bsPutUInt32 ( s, s->combinedCRC );
+      if (s->verbosity >= 2)
+         VPrintf1( "    final combined CRC = 0x%08x\n   ", s->combinedCRC );
+      bsFinishWrite ( s );
+   }
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                        compress.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/project/jni/bzip2/crctable.c b/project/jni/bzip2/crctable.c
new file mode 100644
index 000000000..1fea7e946
--- /dev/null
+++ b/project/jni/bzip2/crctable.c
@@ -0,0 +1,104 @@
+
+/*-------------------------------------------------------------*/
+/*--- Table for doing CRCs                                  ---*/
+/*---                                            crctable.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*--
+  I think this is an implementation of the AUTODIN-II,
+  Ethernet & FDDI 32-bit CRC standard.  Vaguely derived
+  from code by Rob Warnock, in Section 51 of the
+  comp.compression FAQ.
+--*/
+
+UInt32 BZ2_crc32Table[256] = {
+
+   /*-- Ugly, innit? --*/
+
+   0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L,
+   0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L,
+   0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L,
+   0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL,
+   0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L,
+   0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L,
+   0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L,
+   0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL,
+   0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L,
+   0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L,
+   0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L,
+   0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL,
+   0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L,
+   0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L,
+   0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L,
+   0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL,
+   0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL,
+   0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L,
+   0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L,
+   0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL,
+   0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL,
+   0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L,
+   0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L,
+   0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL,
+   0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL,
+   0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L,
+   0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L,
+   0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL,
+   0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL,
+   0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L,
+   0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L,
+   0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL,
+   0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L,
+   0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL,
+   0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL,
+   0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L,
+   0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L,
+   0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL,
+   0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL,
+   0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L,
+   0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L,
+   0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL,
+   0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL,
+   0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L,
+   0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L,
+   0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL,
+   0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL,
+   0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L,
+   0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L,
+   0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL,
+   0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L,
+   0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L,
+   0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L,
+   0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL,
+   0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L,
+   0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L,
+   0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L,
+   0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL,
+   0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L,
+   0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L,
+   0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L,
+   0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL,
+   0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L,
+   0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L
+};
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                        crctable.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/project/jni/bzip2/decompress.c b/project/jni/bzip2/decompress.c
new file mode 100644
index 000000000..311f5668f
--- /dev/null
+++ b/project/jni/bzip2/decompress.c
@@ -0,0 +1,646 @@
+
+/*-------------------------------------------------------------*/
+/*--- Decompression machinery                               ---*/
+/*---                                          decompress.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------------*/
+static
+void makeMaps_d ( DState* s )
+{
+   Int32 i;
+   s->nInUse = 0;
+   for (i = 0; i < 256; i++)
+      if (s->inUse[i]) {
+         s->seqToUnseq[s->nInUse] = i;
+         s->nInUse++;
+      }
+}
+
+
+/*---------------------------------------------------*/
+#define RETURN(rrr)                               \
+   { retVal = rrr; goto save_state_and_return; };
+
+#define GET_BITS(lll,vvv,nnn)                     \
+   case lll: s->state = lll;                      \
+   while (True) {                                 \
+      if (s->bsLive >= nnn) {                     \
+         UInt32 v;                                \
+         v = (s->bsBuff >>                        \
+             (s->bsLive-nnn)) & ((1 << nnn)-1);   \
+         s->bsLive -= nnn;                        \
+         vvv = v;                                 \
+         break;                                   \
+      }                                           \
+      if (s->strm->avail_in == 0) RETURN(BZ_OK);  \
+      s->bsBuff                                   \
+         = (s->bsBuff << 8) |                     \
+           ((UInt32)                              \
+              (*((UChar*)(s->strm->next_in))));   \
+      s->bsLive += 8;                             \
+      s->strm->next_in++;                         \
+      s->strm->avail_in--;                        \
+      s->strm->total_in_lo32++;                   \
+      if (s->strm->total_in_lo32 == 0)            \
+         s->strm->total_in_hi32++;                \
+   }
+
+#define GET_UCHAR(lll,uuu)                        \
+   GET_BITS(lll,uuu,8)
+
+#define GET_BIT(lll,uuu)                          \
+   GET_BITS(lll,uuu,1)
+
+/*---------------------------------------------------*/
+#define GET_MTF_VAL(label1,label2,lval)           \
+{                                                 \
+   if (groupPos == 0) {                           \
+      groupNo++;                                  \
+      if (groupNo >= nSelectors)                  \
+         RETURN(BZ_DATA_ERROR);                   \
+      groupPos = BZ_G_SIZE;                       \
+      gSel = s->selector[groupNo];                \
+      gMinlen = s->minLens[gSel];                 \
+      gLimit = &(s->limit[gSel][0]);              \
+      gPerm = &(s->perm[gSel][0]);                \
+      gBase = &(s->base[gSel][0]);                \
+   }                                              \
+   groupPos--;                                    \
+   zn = gMinlen;                                  \
+   GET_BITS(label1, zvec, zn);                    \
+   while (1) {                                    \
+      if (zn > 20 /* the longest code */)         \
+         RETURN(BZ_DATA_ERROR);                   \
+      if (zvec <= gLimit[zn]) break;              \
+      zn++;                                       \
+      GET_BIT(label2, zj);                        \
+      zvec = (zvec << 1) | zj;                    \
+   };                                             \
+   if (zvec - gBase[zn] < 0                       \
+       || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE)  \
+      RETURN(BZ_DATA_ERROR);                      \
+   lval = gPerm[zvec - gBase[zn]];                \
+}
+
+
+/*---------------------------------------------------*/
+Int32 BZ2_decompress ( DState* s )
+{
+   UChar      uc;
+   Int32      retVal;
+   Int32      minLen, maxLen;
+   bz_stream* strm = s->strm;
+
+   /* stuff that needs to be saved/restored */
+   Int32  i;
+   Int32  j;
+   Int32  t;
+   Int32  alphaSize;
+   Int32  nGroups;
+   Int32  nSelectors;
+   Int32  EOB;
+   Int32  groupNo;
+   Int32  groupPos;
+   Int32  nextSym;
+   Int32  nblockMAX;
+   Int32  nblock;
+   Int32  es;
+   Int32  N;
+   Int32  curr;
+   Int32  zt;
+   Int32  zn; 
+   Int32  zvec;
+   Int32  zj;
+   Int32  gSel;
+   Int32  gMinlen;
+   Int32* gLimit;
+   Int32* gBase;
+   Int32* gPerm;
+
+   if (s->state == BZ_X_MAGIC_1) {
+      /*initialise the save area*/
+      s->save_i           = 0;
+      s->save_j           = 0;
+      s->save_t           = 0;
+      s->save_alphaSize   = 0;
+      s->save_nGroups     = 0;
+      s->save_nSelectors  = 0;
+      s->save_EOB         = 0;
+      s->save_groupNo     = 0;
+      s->save_groupPos    = 0;
+      s->save_nextSym     = 0;
+      s->save_nblockMAX   = 0;
+      s->save_nblock      = 0;
+      s->save_es          = 0;
+      s->save_N           = 0;
+      s->save_curr        = 0;
+      s->save_zt          = 0;
+      s->save_zn          = 0;
+      s->save_zvec        = 0;
+      s->save_zj          = 0;
+      s->save_gSel        = 0;
+      s->save_gMinlen     = 0;
+      s->save_gLimit      = NULL;
+      s->save_gBase       = NULL;
+      s->save_gPerm       = NULL;
+   }
+
+   /*restore from the save area*/
+   i           = s->save_i;
+   j           = s->save_j;
+   t           = s->save_t;
+   alphaSize   = s->save_alphaSize;
+   nGroups     = s->save_nGroups;
+   nSelectors  = s->save_nSelectors;
+   EOB         = s->save_EOB;
+   groupNo     = s->save_groupNo;
+   groupPos    = s->save_groupPos;
+   nextSym     = s->save_nextSym;
+   nblockMAX   = s->save_nblockMAX;
+   nblock      = s->save_nblock;
+   es          = s->save_es;
+   N           = s->save_N;
+   curr        = s->save_curr;
+   zt          = s->save_zt;
+   zn          = s->save_zn; 
+   zvec        = s->save_zvec;
+   zj          = s->save_zj;
+   gSel        = s->save_gSel;
+   gMinlen     = s->save_gMinlen;
+   gLimit      = s->save_gLimit;
+   gBase       = s->save_gBase;
+   gPerm       = s->save_gPerm;
+
+   retVal = BZ_OK;
+
+   switch (s->state) {
+
+      GET_UCHAR(BZ_X_MAGIC_1, uc);
+      if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC);
+
+      GET_UCHAR(BZ_X_MAGIC_2, uc);
+      if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC);
+
+      GET_UCHAR(BZ_X_MAGIC_3, uc)
+      if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC);
+
+      GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
+      if (s->blockSize100k < (BZ_HDR_0 + 1) || 
+          s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC);
+      s->blockSize100k -= BZ_HDR_0;
+
+      if (s->smallDecompress) {
+         s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
+         s->ll4  = BZALLOC( 
+                      ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) 
+                   );
+         if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
+      } else {
+         s->tt  = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
+         if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
+      }
+
+      GET_UCHAR(BZ_X_BLKHDR_1, uc);
+
+      if (uc == 0x17) goto endhdr_2;
+      if (uc != 0x31) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_2, uc);
+      if (uc != 0x41) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_3, uc);
+      if (uc != 0x59) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_4, uc);
+      if (uc != 0x26) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_5, uc);
+      if (uc != 0x53) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_BLKHDR_6, uc);
+      if (uc != 0x59) RETURN(BZ_DATA_ERROR);
+
+      s->currBlockNo++;
+      if (s->verbosity >= 2)
+         VPrintf1 ( "\n    [%d: huff+mtf ", s->currBlockNo );
+ 
+      s->storedBlockCRC = 0;
+      GET_UCHAR(BZ_X_BCRC_1, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_BCRC_2, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_BCRC_3, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_BCRC_4, uc);
+      s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
+
+      GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
+
+      s->origPtr = 0;
+      GET_UCHAR(BZ_X_ORIGPTR_1, uc);
+      s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+      GET_UCHAR(BZ_X_ORIGPTR_2, uc);
+      s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+      GET_UCHAR(BZ_X_ORIGPTR_3, uc);
+      s->origPtr = (s->origPtr << 8) | ((Int32)uc);
+
+      if (s->origPtr < 0)
+         RETURN(BZ_DATA_ERROR);
+      if (s->origPtr > 10 + 100000*s->blockSize100k) 
+         RETURN(BZ_DATA_ERROR);
+
+      /*--- Receive the mapping table ---*/
+      for (i = 0; i < 16; i++) {
+         GET_BIT(BZ_X_MAPPING_1, uc);
+         if (uc == 1) 
+            s->inUse16[i] = True; else 
+            s->inUse16[i] = False;
+      }
+
+      for (i = 0; i < 256; i++) s->inUse[i] = False;
+
+      for (i = 0; i < 16; i++)
+         if (s->inUse16[i])
+            for (j = 0; j < 16; j++) {
+               GET_BIT(BZ_X_MAPPING_2, uc);
+               if (uc == 1) s->inUse[i * 16 + j] = True;
+            }
+      makeMaps_d ( s );
+      if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
+      alphaSize = s->nInUse+2;
+
+      /*--- Now the selectors ---*/
+      GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
+      if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR);
+      GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
+      if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
+      for (i = 0; i < nSelectors; i++) {
+         j = 0;
+         while (True) {
+            GET_BIT(BZ_X_SELECTOR_3, uc);
+            if (uc == 0) break;
+            j++;
+            if (j >= nGroups) RETURN(BZ_DATA_ERROR);
+         }
+         s->selectorMtf[i] = j;
+      }
+
+      /*--- Undo the MTF values for the selectors. ---*/
+      {
+         UChar pos[BZ_N_GROUPS], tmp, v;
+         for (v = 0; v < nGroups; v++) pos[v] = v;
+   
+         for (i = 0; i < nSelectors; i++) {
+            v = s->selectorMtf[i];
+            tmp = pos[v];
+            while (v > 0) { pos[v] = pos[v-1]; v--; }
+            pos[0] = tmp;
+            s->selector[i] = tmp;
+         }
+      }
+
+      /*--- Now the coding tables ---*/
+      for (t = 0; t < nGroups; t++) {
+         GET_BITS(BZ_X_CODING_1, curr, 5);
+         for (i = 0; i < alphaSize; i++) {
+            while (True) {
+               if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
+               GET_BIT(BZ_X_CODING_2, uc);
+               if (uc == 0) break;
+               GET_BIT(BZ_X_CODING_3, uc);
+               if (uc == 0) curr++; else curr--;
+            }
+            s->len[t][i] = curr;
+         }
+      }
+
+      /*--- Create the Huffman decoding tables ---*/
+      for (t = 0; t < nGroups; t++) {
+         minLen = 32;
+         maxLen = 0;
+         for (i = 0; i < alphaSize; i++) {
+            if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
+            if (s->len[t][i] < minLen) minLen = s->len[t][i];
+         }
+         BZ2_hbCreateDecodeTables ( 
+            &(s->limit[t][0]), 
+            &(s->base[t][0]), 
+            &(s->perm[t][0]), 
+            &(s->len[t][0]),
+            minLen, maxLen, alphaSize
+         );
+         s->minLens[t] = minLen;
+      }
+
+      /*--- Now the MTF values ---*/
+
+      EOB      = s->nInUse+1;
+      nblockMAX = 100000 * s->blockSize100k;
+      groupNo  = -1;
+      groupPos = 0;
+
+      for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
+
+      /*-- MTF init --*/
+      {
+         Int32 ii, jj, kk;
+         kk = MTFA_SIZE-1;
+         for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
+            for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
+               s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
+               kk--;
+            }
+            s->mtfbase[ii] = kk + 1;
+         }
+      }
+      /*-- end MTF init --*/
+
+      nblock = 0;
+      GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
+
+      while (True) {
+
+         if (nextSym == EOB) break;
+
+         if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
+
+            es = -1;
+            N = 1;
+            do {
+               /* Check that N doesn't get too big, so that es doesn't
+                  go negative.  The maximum value that can be
+                  RUNA/RUNB encoded is equal to the block size (post
+                  the initial RLE), viz, 900k, so bounding N at 2
+                  million should guard against overflow without
+                  rejecting any legitimate inputs. */
+               if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR);
+               if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
+               if (nextSym == BZ_RUNB) es = es + (1+1) * N;
+               N = N * 2;
+               GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
+            }
+               while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
+
+            es++;
+            uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
+            s->unzftab[uc] += es;
+
+            if (s->smallDecompress)
+               while (es > 0) {
+                  if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+                  s->ll16[nblock] = (UInt16)uc;
+                  nblock++;
+                  es--;
+               }
+            else
+               while (es > 0) {
+                  if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+                  s->tt[nblock] = (UInt32)uc;
+                  nblock++;
+                  es--;
+               };
+
+            continue;
+
+         } else {
+
+            if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
+
+            /*-- uc = MTF ( nextSym-1 ) --*/
+            {
+               Int32 ii, jj, kk, pp, lno, off;
+               UInt32 nn;
+               nn = (UInt32)(nextSym - 1);
+
+               if (nn < MTFL_SIZE) {
+                  /* avoid general-case expense */
+                  pp = s->mtfbase[0];
+                  uc = s->mtfa[pp+nn];
+                  while (nn > 3) {
+                     Int32 z = pp+nn;
+                     s->mtfa[(z)  ] = s->mtfa[(z)-1];
+                     s->mtfa[(z)-1] = s->mtfa[(z)-2];
+                     s->mtfa[(z)-2] = s->mtfa[(z)-3];
+                     s->mtfa[(z)-3] = s->mtfa[(z)-4];
+                     nn -= 4;
+                  }
+                  while (nn > 0) { 
+                     s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; 
+                  };
+                  s->mtfa[pp] = uc;
+               } else { 
+                  /* general case */
+                  lno = nn / MTFL_SIZE;
+                  off = nn % MTFL_SIZE;
+                  pp = s->mtfbase[lno] + off;
+                  uc = s->mtfa[pp];
+                  while (pp > s->mtfbase[lno]) { 
+                     s->mtfa[pp] = s->mtfa[pp-1]; pp--; 
+                  };
+                  s->mtfbase[lno]++;
+                  while (lno > 0) {
+                     s->mtfbase[lno]--;
+                     s->mtfa[s->mtfbase[lno]] 
+                        = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
+                     lno--;
+                  }
+                  s->mtfbase[0]--;
+                  s->mtfa[s->mtfbase[0]] = uc;
+                  if (s->mtfbase[0] == 0) {
+                     kk = MTFA_SIZE-1;
+                     for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
+                        for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
+                           s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
+                           kk--;
+                        }
+                        s->mtfbase[ii] = kk + 1;
+                     }
+                  }
+               }
+            }
+            /*-- end uc = MTF ( nextSym-1 ) --*/
+
+            s->unzftab[s->seqToUnseq[uc]]++;
+            if (s->smallDecompress)
+               s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
+               s->tt[nblock]   = (UInt32)(s->seqToUnseq[uc]);
+            nblock++;
+
+            GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
+            continue;
+         }
+      }
+
+      /* Now we know what nblock is, we can do a better sanity
+         check on s->origPtr.
+      */
+      if (s->origPtr < 0 || s->origPtr >= nblock)
+         RETURN(BZ_DATA_ERROR);
+
+      /*-- Set up cftab to facilitate generation of T^(-1) --*/
+      /* Check: unzftab entries in range. */
+      for (i = 0; i <= 255; i++) {
+         if (s->unzftab[i] < 0 || s->unzftab[i] > nblock)
+            RETURN(BZ_DATA_ERROR);
+      }
+      /* Actually generate cftab. */
+      s->cftab[0] = 0;
+      for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
+      for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
+      /* Check: cftab entries in range. */
+      for (i = 0; i <= 256; i++) {
+         if (s->cftab[i] < 0 || s->cftab[i] > nblock) {
+            /* s->cftab[i] can legitimately be == nblock */
+            RETURN(BZ_DATA_ERROR);
+         }
+      }
+      /* Check: cftab entries non-descending. */
+      for (i = 1; i <= 256; i++) {
+         if (s->cftab[i-1] > s->cftab[i]) {
+            RETURN(BZ_DATA_ERROR);
+         }
+      }
+
+      s->state_out_len = 0;
+      s->state_out_ch  = 0;
+      BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
+      s->state = BZ_X_OUTPUT;
+      if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
+
+      if (s->smallDecompress) {
+
+         /*-- Make a copy of cftab, used in generation of T --*/
+         for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
+
+         /*-- compute the T vector --*/
+         for (i = 0; i < nblock; i++) {
+            uc = (UChar)(s->ll16[i]);
+            SET_LL(i, s->cftabCopy[uc]);
+            s->cftabCopy[uc]++;
+         }
+
+         /*-- Compute T^(-1) by pointer reversal on T --*/
+         i = s->origPtr;
+         j = GET_LL(i);
+         do {
+            Int32 tmp = GET_LL(j);
+            SET_LL(j, i);
+            i = j;
+            j = tmp;
+         }
+            while (i != s->origPtr);
+
+         s->tPos = s->origPtr;
+         s->nblock_used = 0;
+         if (s->blockRandomised) {
+            BZ_RAND_INIT_MASK;
+            BZ_GET_SMALL(s->k0); s->nblock_used++;
+            BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; 
+         } else {
+            BZ_GET_SMALL(s->k0); s->nblock_used++;
+         }
+
+      } else {
+
+         /*-- compute the T^(-1) vector --*/
+         for (i = 0; i < nblock; i++) {
+            uc = (UChar)(s->tt[i] & 0xff);
+            s->tt[s->cftab[uc]] |= (i << 8);
+            s->cftab[uc]++;
+         }
+
+         s->tPos = s->tt[s->origPtr] >> 8;
+         s->nblock_used = 0;
+         if (s->blockRandomised) {
+            BZ_RAND_INIT_MASK;
+            BZ_GET_FAST(s->k0); s->nblock_used++;
+            BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; 
+         } else {
+            BZ_GET_FAST(s->k0); s->nblock_used++;
+         }
+
+      }
+
+      RETURN(BZ_OK);
+
+
+
+    endhdr_2:
+
+      GET_UCHAR(BZ_X_ENDHDR_2, uc);
+      if (uc != 0x72) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_3, uc);
+      if (uc != 0x45) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_4, uc);
+      if (uc != 0x38) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_5, uc);
+      if (uc != 0x50) RETURN(BZ_DATA_ERROR);
+      GET_UCHAR(BZ_X_ENDHDR_6, uc);
+      if (uc != 0x90) RETURN(BZ_DATA_ERROR);
+
+      s->storedCombinedCRC = 0;
+      GET_UCHAR(BZ_X_CCRC_1, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_CCRC_2, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_CCRC_3, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+      GET_UCHAR(BZ_X_CCRC_4, uc);
+      s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
+
+      s->state = BZ_X_IDLE;
+      RETURN(BZ_STREAM_END);
+
+      default: AssertH ( False, 4001 );
+   }
+
+   AssertH ( False, 4002 );
+
+   save_state_and_return:
+
+   s->save_i           = i;
+   s->save_j           = j;
+   s->save_t           = t;
+   s->save_alphaSize   = alphaSize;
+   s->save_nGroups     = nGroups;
+   s->save_nSelectors  = nSelectors;
+   s->save_EOB         = EOB;
+   s->save_groupNo     = groupNo;
+   s->save_groupPos    = groupPos;
+   s->save_nextSym     = nextSym;
+   s->save_nblockMAX   = nblockMAX;
+   s->save_nblock      = nblock;
+   s->save_es          = es;
+   s->save_N           = N;
+   s->save_curr        = curr;
+   s->save_zt          = zt;
+   s->save_zn          = zn;
+   s->save_zvec        = zvec;
+   s->save_zj          = zj;
+   s->save_gSel        = gSel;
+   s->save_gMinlen     = gMinlen;
+   s->save_gLimit      = gLimit;
+   s->save_gBase       = gBase;
+   s->save_gPerm       = gPerm;
+
+   return retVal;   
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                      decompress.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/project/jni/bzip2/huffman.c b/project/jni/bzip2/huffman.c
new file mode 100644
index 000000000..2283fdbc5
--- /dev/null
+++ b/project/jni/bzip2/huffman.c
@@ -0,0 +1,205 @@
+
+/*-------------------------------------------------------------*/
+/*--- Huffman coding low-level stuff                        ---*/
+/*---                                             huffman.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+/*---------------------------------------------------*/
+#define WEIGHTOF(zz0)  ((zz0) & 0xffffff00)
+#define DEPTHOF(zz1)   ((zz1) & 0x000000ff)
+#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3))
+
+#define ADDWEIGHTS(zw1,zw2)                           \
+   (WEIGHTOF(zw1)+WEIGHTOF(zw2)) |                    \
+   (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2)))
+
+#define UPHEAP(z)                                     \
+{                                                     \
+   Int32 zz, tmp;                                     \
+   zz = z; tmp = heap[zz];                            \
+   while (weight[tmp] < weight[heap[zz >> 1]]) {      \
+      heap[zz] = heap[zz >> 1];                       \
+      zz >>= 1;                                       \
+   }                                                  \
+   heap[zz] = tmp;                                    \
+}
+
+#define DOWNHEAP(z)                                   \
+{                                                     \
+   Int32 zz, yy, tmp;                                 \
+   zz = z; tmp = heap[zz];                            \
+   while (True) {                                     \
+      yy = zz << 1;                                   \
+      if (yy > nHeap) break;                          \
+      if (yy < nHeap &&                               \
+          weight[heap[yy+1]] < weight[heap[yy]])      \
+         yy++;                                        \
+      if (weight[tmp] < weight[heap[yy]]) break;      \
+      heap[zz] = heap[yy];                            \
+      zz = yy;                                        \
+   }                                                  \
+   heap[zz] = tmp;                                    \
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbMakeCodeLengths ( UChar *len, 
+                             Int32 *freq,
+                             Int32 alphaSize,
+                             Int32 maxLen )
+{
+   /*--
+      Nodes and heap entries run from 1.  Entry 0
+      for both the heap and nodes is a sentinel.
+   --*/
+   Int32 nNodes, nHeap, n1, n2, i, j, k;
+   Bool  tooLong;
+
+   Int32 heap   [ BZ_MAX_ALPHA_SIZE + 2 ];
+   Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ];
+   Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; 
+
+   for (i = 0; i < alphaSize; i++)
+      weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
+
+   while (True) {
+
+      nNodes = alphaSize;
+      nHeap = 0;
+
+      heap[0] = 0;
+      weight[0] = 0;
+      parent[0] = -2;
+
+      for (i = 1; i <= alphaSize; i++) {
+         parent[i] = -1;
+         nHeap++;
+         heap[nHeap] = i;
+         UPHEAP(nHeap);
+      }
+
+      AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 );
+   
+      while (nHeap > 1) {
+         n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
+         n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1);
+         nNodes++;
+         parent[n1] = parent[n2] = nNodes;
+         weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]);
+         parent[nNodes] = -1;
+         nHeap++;
+         heap[nHeap] = nNodes;
+         UPHEAP(nHeap);
+      }
+
+      AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 );
+
+      tooLong = False;
+      for (i = 1; i <= alphaSize; i++) {
+         j = 0;
+         k = i;
+         while (parent[k] >= 0) { k = parent[k]; j++; }
+         len[i-1] = j;
+         if (j > maxLen) tooLong = True;
+      }
+      
+      if (! tooLong) break;
+
+      /* 17 Oct 04: keep-going condition for the following loop used
+         to be 'i < alphaSize', which missed the last element,
+         theoretically leading to the possibility of the compressor
+         looping.  However, this count-scaling step is only needed if
+         one of the generated Huffman code words is longer than
+         maxLen, which up to and including version 1.0.2 was 20 bits,
+         which is extremely unlikely.  In version 1.0.3 maxLen was
+         changed to 17 bits, which has minimal effect on compression
+         ratio, but does mean this scaling step is used from time to
+         time, enough to verify that it works.
+
+         This means that bzip2-1.0.3 and later will only produce
+         Huffman codes with a maximum length of 17 bits.  However, in
+         order to preserve backwards compatibility with bitstreams
+         produced by versions pre-1.0.3, the decompressor must still
+         handle lengths of up to 20. */
+
+      for (i = 1; i <= alphaSize; i++) {
+         j = weight[i] >> 8;
+         j = 1 + (j / 2);
+         weight[i] = j << 8;
+      }
+   }
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbAssignCodes ( Int32 *code,
+                         UChar *length,
+                         Int32 minLen,
+                         Int32 maxLen,
+                         Int32 alphaSize )
+{
+   Int32 n, vec, i;
+
+   vec = 0;
+   for (n = minLen; n <= maxLen; n++) {
+      for (i = 0; i < alphaSize; i++)
+         if (length[i] == n) { code[i] = vec; vec++; };
+      vec <<= 1;
+   }
+}
+
+
+/*---------------------------------------------------*/
+void BZ2_hbCreateDecodeTables ( Int32 *limit,
+                                Int32 *base,
+                                Int32 *perm,
+                                UChar *length,
+                                Int32 minLen,
+                                Int32 maxLen,
+                                Int32 alphaSize )
+{
+   Int32 pp, i, j, vec;
+
+   pp = 0;
+   for (i = minLen; i <= maxLen; i++)
+      for (j = 0; j < alphaSize; j++)
+         if (length[j] == i) { perm[pp] = j; pp++; };
+
+   for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0;
+   for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
+
+   for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1];
+
+   for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0;
+   vec = 0;
+
+   for (i = minLen; i <= maxLen; i++) {
+      vec += (base[i+1] - base[i]);
+      limit[i] = vec-1;
+      vec <<= 1;
+   }
+   for (i = minLen + 1; i <= maxLen; i++)
+      base[i] = ((limit[i-1] + 1) << 1) - base[i];
+}
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                         huffman.c ---*/
+/*-------------------------------------------------------------*/
diff --git a/project/jni/bzip2/include/bzlib.h b/project/jni/bzip2/include/bzlib.h
new file mode 100644
index 000000000..8277123da
--- /dev/null
+++ b/project/jni/bzip2/include/bzlib.h
@@ -0,0 +1,282 @@
+
+/*-------------------------------------------------------------*/
+/*--- Public header file for the library.                   ---*/
+/*---                                               bzlib.h ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#ifndef _BZLIB_H
+#define _BZLIB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define BZ_RUN               0
+#define BZ_FLUSH             1
+#define BZ_FINISH            2
+
+#define BZ_OK                0
+#define BZ_RUN_OK            1
+#define BZ_FLUSH_OK          2
+#define BZ_FINISH_OK         3
+#define BZ_STREAM_END        4
+#define BZ_SEQUENCE_ERROR    (-1)
+#define BZ_PARAM_ERROR       (-2)
+#define BZ_MEM_ERROR         (-3)
+#define BZ_DATA_ERROR        (-4)
+#define BZ_DATA_ERROR_MAGIC  (-5)
+#define BZ_IO_ERROR          (-6)
+#define BZ_UNEXPECTED_EOF    (-7)
+#define BZ_OUTBUFF_FULL      (-8)
+#define BZ_CONFIG_ERROR      (-9)
+
+typedef 
+   struct {
+      char *next_in;
+      unsigned int avail_in;
+      unsigned int total_in_lo32;
+      unsigned int total_in_hi32;
+
+      char *next_out;
+      unsigned int avail_out;
+      unsigned int total_out_lo32;
+      unsigned int total_out_hi32;
+
+      void *state;
+
+      void *(*bzalloc)(void *,int,int);
+      void (*bzfree)(void *,void *);
+      void *opaque;
+   } 
+   bz_stream;
+
+
+#ifndef BZ_IMPORT
+#define BZ_EXPORT
+#endif
+
+#ifndef BZ_NO_STDIO
+/* Need a definitition for FILE */
+#include 
+#endif
+
+#ifdef _WIN32
+#   include 
+#   ifdef small
+      /* windows.h define small to char */
+#      undef small
+#   endif
+#   ifdef BZ_EXPORT
+#   define BZ_API(func) WINAPI func
+#   define BZ_EXTERN extern
+#   else
+   /* import windows dll dynamically */
+#   define BZ_API(func) (WINAPI * func)
+#   define BZ_EXTERN
+#   endif
+#else
+#   define BZ_API(func) func
+#   define BZ_EXTERN extern
+#endif
+
+
+/*-- Core (low-level) library functions --*/
+
+BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( 
+      bz_stream* strm, 
+      int        blockSize100k, 
+      int        verbosity, 
+      int        workFactor 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompress) ( 
+      bz_stream* strm, 
+      int action 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( 
+      bz_stream* strm 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( 
+      bz_stream *strm, 
+      int       verbosity, 
+      int       small
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( 
+      bz_stream* strm 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( 
+      bz_stream *strm 
+   );
+
+
+
+/*-- High(er) level library functions --*/
+
+#ifndef BZ_NO_STDIO
+#define BZ_MAX_UNUSED 5000
+
+typedef void BZFILE;
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( 
+      int*  bzerror,   
+      FILE* f, 
+      int   verbosity, 
+      int   small,
+      void* unused,    
+      int   nUnused 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( 
+      int*    bzerror, 
+      BZFILE* b 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( 
+      int*    bzerror, 
+      BZFILE* b, 
+      void**  unused,  
+      int*    nUnused 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzRead) ( 
+      int*    bzerror, 
+      BZFILE* b, 
+      void*   buf, 
+      int     len 
+   );
+
+BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( 
+      int*  bzerror,      
+      FILE* f, 
+      int   blockSize100k, 
+      int   verbosity, 
+      int   workFactor 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzWrite) ( 
+      int*    bzerror, 
+      BZFILE* b, 
+      void*   buf, 
+      int     len 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( 
+      int*          bzerror, 
+      BZFILE*       b, 
+      int           abandon, 
+      unsigned int* nbytes_in, 
+      unsigned int* nbytes_out 
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( 
+      int*          bzerror, 
+      BZFILE*       b, 
+      int           abandon, 
+      unsigned int* nbytes_in_lo32, 
+      unsigned int* nbytes_in_hi32, 
+      unsigned int* nbytes_out_lo32, 
+      unsigned int* nbytes_out_hi32
+   );
+#endif
+
+
+/*-- Utility functions --*/
+
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( 
+      char*         dest, 
+      unsigned int* destLen,
+      char*         source, 
+      unsigned int  sourceLen,
+      int           blockSize100k, 
+      int           verbosity, 
+      int           workFactor 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( 
+      char*         dest, 
+      unsigned int* destLen,
+      char*         source, 
+      unsigned int  sourceLen,
+      int           small, 
+      int           verbosity 
+   );
+
+
+/*--
+   Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
+   to support better zlib compatibility.
+   This code is not _officially_ part of libbzip2 (yet);
+   I haven't tested it, documented it, or considered the
+   threading-safeness of it.
+   If this code breaks, please contact both Yoshioka and me.
+--*/
+
+BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) (
+      void
+   );
+
+#ifndef BZ_NO_STDIO
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) (
+      const char *path,
+      const char *mode
+   );
+
+BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) (
+      int        fd,
+      const char *mode
+   );
+         
+BZ_EXTERN int BZ_API(BZ2_bzread) (
+      BZFILE* b, 
+      void* buf, 
+      int len 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzwrite) (
+      BZFILE* b, 
+      void*   buf, 
+      int     len 
+   );
+
+BZ_EXTERN int BZ_API(BZ2_bzflush) (
+      BZFILE* b
+   );
+
+BZ_EXTERN void BZ_API(BZ2_bzclose) (
+      BZFILE* b
+   );
+
+BZ_EXTERN const char * BZ_API(BZ2_bzerror) (
+      BZFILE *b, 
+      int    *errnum
+   );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*-------------------------------------------------------------*/
+/*--- end                                           bzlib.h ---*/
+/*-------------------------------------------------------------*/
diff --git a/project/jni/bzip2/randtable.c b/project/jni/bzip2/randtable.c
new file mode 100644
index 000000000..6d6245990
--- /dev/null
+++ b/project/jni/bzip2/randtable.c
@@ -0,0 +1,84 @@
+
+/*-------------------------------------------------------------*/
+/*--- Table for randomising repetitive blocks               ---*/
+/*---                                           randtable.c ---*/
+/*-------------------------------------------------------------*/
+
+/* ------------------------------------------------------------------
+   This file is part of bzip2/libbzip2, a program and library for
+   lossless, block-sorting data compression.
+
+   bzip2/libbzip2 version 1.0.6 of 6 September 2010
+   Copyright (C) 1996-2010 Julian Seward 
+
+   Please read the WARNING, DISCLAIMER and PATENTS sections in the 
+   README file.
+
+   This program is released under the terms of the license contained
+   in the file LICENSE.
+   ------------------------------------------------------------------ */
+
+
+#include "bzlib_private.h"
+
+
+/*---------------------------------------------*/
+Int32 BZ2_rNums[512] = { 
+   619, 720, 127, 481, 931, 816, 813, 233, 566, 247, 
+   985, 724, 205, 454, 863, 491, 741, 242, 949, 214, 
+   733, 859, 335, 708, 621, 574, 73, 654, 730, 472, 
+   419, 436, 278, 496, 867, 210, 399, 680, 480, 51, 
+   878, 465, 811, 169, 869, 675, 611, 697, 867, 561, 
+   862, 687, 507, 283, 482, 129, 807, 591, 733, 623, 
+   150, 238, 59, 379, 684, 877, 625, 169, 643, 105, 
+   170, 607, 520, 932, 727, 476, 693, 425, 174, 647, 
+   73, 122, 335, 530, 442, 853, 695, 249, 445, 515, 
+   909, 545, 703, 919, 874, 474, 882, 500, 594, 612, 
+   641, 801, 220, 162, 819, 984, 589, 513, 495, 799, 
+   161, 604, 958, 533, 221, 400, 386, 867, 600, 782, 
+   382, 596, 414, 171, 516, 375, 682, 485, 911, 276, 
+   98, 553, 163, 354, 666, 933, 424, 341, 533, 870, 
+   227, 730, 475, 186, 263, 647, 537, 686, 600, 224, 
+   469, 68, 770, 919, 190, 373, 294, 822, 808, 206, 
+   184, 943, 795, 384, 383, 461, 404, 758, 839, 887, 
+   715, 67, 618, 276, 204, 918, 873, 777, 604, 560, 
+   951, 160, 578, 722, 79, 804, 96, 409, 713, 940, 
+   652, 934, 970, 447, 318, 353, 859, 672, 112, 785, 
+   645, 863, 803, 350, 139, 93, 354, 99, 820, 908, 
+   609, 772, 154, 274, 580, 184, 79, 626, 630, 742, 
+   653, 282, 762, 623, 680, 81, 927, 626, 789, 125, 
+   411, 521, 938, 300, 821, 78, 343, 175, 128, 250, 
+   170, 774, 972, 275, 999, 639, 495, 78, 352, 126, 
+   857, 956, 358, 619, 580, 124, 737, 594, 701, 612, 
+   669, 112, 134, 694, 363, 992, 809, 743, 168, 974, 
+   944, 375, 748, 52, 600, 747, 642, 182, 862, 81, 
+   344, 805, 988, 739, 511, 655, 814, 334, 249, 515, 
+   897, 955, 664, 981, 649, 113, 974, 459, 893, 228, 
+   433, 837, 553, 268, 926, 240, 102, 654, 459, 51, 
+   686, 754, 806, 760, 493, 403, 415, 394, 687, 700, 
+   946, 670, 656, 610, 738, 392, 760, 799, 887, 653, 
+   978, 321, 576, 617, 626, 502, 894, 679, 243, 440, 
+   680, 879, 194, 572, 640, 724, 926, 56, 204, 700, 
+   707, 151, 457, 449, 797, 195, 791, 558, 945, 679, 
+   297, 59, 87, 824, 713, 663, 412, 693, 342, 606, 
+   134, 108, 571, 364, 631, 212, 174, 643, 304, 329, 
+   343, 97, 430, 751, 497, 314, 983, 374, 822, 928, 
+   140, 206, 73, 263, 980, 736, 876, 478, 430, 305, 
+   170, 514, 364, 692, 829, 82, 855, 953, 676, 246, 
+   369, 970, 294, 750, 807, 827, 150, 790, 288, 923, 
+   804, 378, 215, 828, 592, 281, 565, 555, 710, 82, 
+   896, 831, 547, 261, 524, 462, 293, 465, 502, 56, 
+   661, 821, 976, 991, 658, 869, 905, 758, 745, 193, 
+   768, 550, 608, 933, 378, 286, 215, 979, 792, 961, 
+   61, 688, 793, 644, 986, 403, 106, 366, 905, 644, 
+   372, 567, 466, 434, 645, 210, 389, 550, 919, 135, 
+   780, 773, 635, 389, 707, 100, 626, 958, 165, 504, 
+   920, 176, 193, 713, 857, 265, 203, 50, 668, 108, 
+   645, 990, 626, 197, 510, 357, 358, 850, 858, 364, 
+   936, 638
+};
+
+
+/*-------------------------------------------------------------*/
+/*--- end                                       randtable.c ---*/
+/*-------------------------------------------------------------*/